Proste zadanie maturalne

0

Przygotowując się do matury, rozpocząłem od zadania o treści:

Następujące dwa punkty są definicją prostego wyrażenia arytmetycznego W oraz określeniem sposobu obliczania jego wartości wart(W):
1) dowolna nieujemna, jednocyfrowa liczba całkowita L jest prostym wyrażeniem arytmetycznym W; wartością takiego wyrażenia jest L, czyli wart(L)=L;
2) jeżli W1 i W2 są prostymi wyrażeniami arytmetycznymi, a op jest jednym ze znaków działania dwuargumentowego: +, – lub *, to W = W1W2op jest również prostym wyrażeniem arytmetycznym i jego wartosć wynosi: wart(W) = wart(W1) op wart(W2).

Przykłady:
Jeżeli W = 6, to wart(W) = 6
Jeżeli W = 28–, to wart(W) = 2 – 8 = – 6
Jeżeli W = 281–*, to wart(W) = 2 * (8 – 1) = 14
Jeżeli W = 9, to wart(W) = 9
Jeżeli W = 47–, to wart(W) = -3
Jeżeli W = 25+17–*32++, to wart(W) = -37

Napisz program, który obliczy wartość danego wyrażenia W.

Chciałbym tylko kogoś prosić o weryfikację mojego rozwiązania:

 #include <iostream>
#include <clocale>
#include <cstdlib>
using namespace std;

const int MAX_HEAP_SIZE = 127; // Ostatni poziom musi pomieścić maksymalnie 40 cyfr,z tego wynika iż łącznie węzłów musi być 127 (7 poziom pomieści 64 węzły)
int heap[MAX_HEAP_SIZE + 1];
bool isSignTab[MAX_HEAP_SIZE + 1]; // Tablica przechowująca czy w danym wierzchołku znajduje się znak: +,-,*

inline int ToInt(const char c) { return (int)c - 48; }
inline int Count(int a, int b, char sign);

int main()
{
    string input;
    cin >> input;

    /* Ustawienie kopca na zasadzie:
        -> jeżeli obecny znak to +/-/* to kolejnym indexem będzie jego prawy syn (2*i+1)
        -> Jeżeli obecny znak to liczba stojąca na nieparzystym indeksie, to kolejnym indeksem będzie jego brat (i-1)
        -> jeżeli onecny znak to liczba stojąca na parzystym indeksie, to kolejnym indeksem brat jego ojca ((i/2)-1)

        Dodatkowo znaki są "wczytywane od prawej do lewej, wynika to z reguły praw działań (odejmowanie nie jest przemienne).
        */
    for(int i = input.size() - 1, heapIndex = 1; i >= 0; i--)
    {
        bool isSign = !isdigit(input[i]);
        isSignTab[heapIndex] = isSign;

        heap[heapIndex] = (isSign) ? input[i] : ToInt(input[i]);

        if(isSign) heapIndex = 2*heapIndex + 1;
        else if(heapIndex%2 != 0) heapIndex--;
        else heapIndex = (heapIndex/2) - 1;
    }

    /* Przeszukujemy kopiec z liści ku korzeniu */
    for(int i = MAX_HEAP_SIZE; i >= 1; i-- )
    {
        if(isSignTab[i] == true)
        {
            heap[i] = Count(heap[2*i], heap[2*i+1], heap[i]);
        }
    }

    cout << "Wynik: " << heap[1] << endl;
}

int Count(int a, int b, char sign)
{
    switch(sign)
    {
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
    }
}

Niestety nie znalazłem testów do tego zadania, a przy okazji może ktoś zapoda lepszą metodę, bo moja pewnie nie jest optymalna.

0

Nie podeślę testów, ale na pierwszy rzut oka wydaje mi się, że można to zrobić sprytniej.

  1. Tworzymy stos S.
  2. Dla każdego znaku c
    --> Jeśli c jest liczbą, to wrzuć na stos S.
    --> W przeciwnym wypadku zdejmij 2 elementy z S i wykonaj na nich operacje zdefiniowaną przez c. Wynik wrzuć na stos S.
  3. Wynikiem jest pierwsza (i jedyna) wartość na stosie.
2

Strasznie przekombinowałeś:

#include <stack>
#include <cstdio>
#include <cctype>
using namespace std;

int pop(stack<int> &S) { int v=S.top(); S.pop(); return v; }

int main()
  {
   while(true)
     {
      stack<int> S;
      for(int ch;(ch=getchar())!='\n';)
        {
         if(isdigit(ch)) S.push(ch-'0');
         else if(ch=='+') S.top()+=pop(S);
         else if(ch=='*') S.top()*=pop(S);
         else if(ch=='-') S.top()-=pop(S);
         else if(ch==EOF) return 0;
        }
      printf("%d\n",S.top());
     }
  }

http://ideone.com/FyUFyt

1 użytkowników online, w tym zalogowanych: 0, gości: 1