Advertisement
Hydron

Brr

Apr 29th, 2022
866
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.60 KB | None | 0 0
  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. class Parser{
  6.     static vector < string > get_parameters(string &expression){
  7.         /// Функція, яка повертатиме список параметрів, які були передані в операцію.
  8.         size_t i = 0;
  9.         while (expression[i] != '(') i ++;
  10.         string tmp = "";
  11.         vector < string > res;
  12.         int scope = 0;
  13.         for (size_t j=i+1; j<expression.length()-1; j++){
  14.             if (expression[j] == ',' && scope == 0){
  15.                 res.push_back(tmp);
  16.                 tmp = "";
  17.             }else{
  18.                 tmp += expression[j];
  19.                 if (expression[j] == '(') scope ++;
  20.                 else if (expression[j] == ')') scope --;
  21.             }
  22.         }
  23.         res.push_back(tmp);
  24.         return res;
  25.     }
  26.  
  27. public:
  28.     static string parse(string &expression){
  29.         /// Для початку, видалимо всі пробіли, щоб не заважали.
  30.         string tmp = "";
  31.         for (char &c: expression){
  32.             if (c != ' '){
  33.                 tmp += c;
  34.             }
  35.         }
  36.         expression = tmp;
  37.  
  38.         stack < pair < string, size_t > > operations;
  39.         stack < pair< bool, size_t > > values;
  40.         /// Стек "values" буде зберігати всі значення, які повинні в подальшому опинитися серед параметрів стеку "operations".
  41.         /// Також, кожне значення буде "пам'ятати", до якої операції воно повинно "впасти" як параметр
  42.         vector < bool > values_tmp; /// Вектор, який міститиме всі параметри, передані в операцію, яка зараз розглядається
  43.         bool can_be_processed; /// =true, якщо операція була опрацьована, маючи дані зі стеку "values".
  44.         operations.push({expression, (size_t)0});
  45.         while(!operations.empty()){
  46.             string v = operations.top().first;
  47.             size_t return_pos = operations.top().second; /// Позиція, де має бути вставлений результат цієї операції.
  48.             size_t cur_pos = operations.size(); /// Позиція цієї операції.
  49.             can_be_processed = true; /// Припускаємо, що змогли опрацювати операцію.
  50.             for (string param: get_parameters(v)){ /// йдемо по списку параметрів
  51.                 /// Якщо параметр - це не вираз, який має бути опрацьований, а значення, то просто кидаємо його у вектор
  52.                 if (param == "false"){
  53.                     values_tmp.push_back(false);
  54.                 }else{
  55.                     if (param == "true"){
  56.                         values_tmp.push_back(true);
  57.                     }else{
  58.                             /// Інакше, пробуємо підставити результат зі стеку значень в цю операцію.
  59.                         if (values.size() == 0 || values.top().second != cur_pos){
  60.                             /// Якщо нема підходящого значення, то додаємо операцію на опрацювання і кажемо, що операція, яка зараз розглядається, не була завершена
  61.                             operations.push({param, cur_pos});
  62.                             can_be_processed = false;
  63.                         }else{
  64.                             /// Якщо є підходяще значення, то витягаємо його зі стеку, кидаємо у вектор
  65.                             values_tmp.push_back(values.top().first);
  66.                             values.pop();
  67.                         }
  68.                     }
  69.                 }
  70.             }
  71.             if (can_be_processed){
  72.                 /// Якщо операцію було опрацьовано успішно, то обчислюємо її значення, використовуючи вектор значень її параметрів.
  73.                 if (v[0] == 'n'){
  74.                     values.push({!values_tmp[0], return_pos});
  75.                 }else{
  76.                     if (v[0] == 'a'){
  77.                         bool res = true;
  78.                         for (bool p: values_tmp){
  79.                             res = (res && p);
  80.                         }
  81.                         values.push({res, return_pos});
  82.                     }else{
  83.                         bool res = false;
  84.                         for (bool p: values_tmp){
  85.                             res = (res || p);
  86.                         }
  87.                         values.push({res, return_pos});
  88.                     }
  89.                 }
  90.                 operations.pop(); /// Видаляємо операцію зі стеку невиконаних.
  91.             }
  92.             values_tmp.clear(); /// Очищаємо вектор параметрів цієї операції, щоб перейти до наступної.
  93.         }
  94.         if (values.top().first) return "true";
  95.         else return "false";
  96.     }
  97.  
  98.     static void run(){ /// Функція для перевірки роботи класу. Відкриває файл input.txt, бере звідти логічний вираз і обраховує його.
  99.         FILE *f = freopen("input.txt", "r", stdin);
  100.         string s;
  101.         getline(cin, s);
  102.         cout << s+" -> ";
  103.         cout << parse(s) << '\n';
  104.     }
  105. };
  106.  
  107. class Polish{
  108.  
  109.     static void place_brackets(string &s){
  110.         /// Функція, яка видаляє пробіли з виразу і розставляє дужки навколо всіх операцій множення (Бо це найпріорітетніша операція і дужки значно спрощують роботу)
  111.         string t = "";
  112.         for (char c: s){
  113.             if (c != ' ') t += c;
  114.         }
  115.         s = t;
  116.         size_t i = 0;
  117.         /// Цей цикл знаходить множення, йде вліво, поки треба і ставить відкриваючу дужку, потім аналогічно вправо і ставить закриваючу дужку.
  118.         while(i < s.length()){
  119.             if (s[i] == '*'){
  120.                 if (s[i-1] == ')'){
  121.                     int scope = 0;
  122.                     for (int j=i-1; j>-1; j--){
  123.                         if (s[j] == ')') scope ++;
  124.                         else{
  125.                             if (s[j] == '(') scope --;
  126.                         }
  127.                         if (scope == 0){
  128.                             s = s.substr(0, j) + "(" + s.substr(j, s.length()-j);
  129.                             break;
  130.                         }
  131.                     }
  132.                 }else{
  133.                     bool was = false;
  134.                     for (int j=i-1; j>-1; j--){
  135.                         if (s[j] > '9' || s[j] < '0'){
  136.                             was = true;
  137.                             s = s.substr(0, j+1) + "(" + s.substr(j+1, s.length()-j-1);
  138.                             break;
  139.                         }
  140.                     }
  141.                     if (was == false){
  142.                         s = "(" + s;
  143.                     }
  144.                 }
  145.                 i ++;
  146.                 if (s[i+1] == '('){
  147.                     int scope = 0;
  148.                     i ++;
  149.                     while(i < s.length()){
  150.                         if (s[i] == '(') scope ++;
  151.                         else if (s[i] == ')') scope --;
  152.                         if (scope == 0) break;
  153.                         i ++;
  154.                     }
  155.                     s = s.substr(0, i+1) + ")" + s.substr(i+1, max((size_t)0, s.length() - (i+1)));
  156.                 }else{
  157.                     while(i+1 < s.length() && s[i+1] <= '9' && s[i+1] >= '0'){
  158.                         i ++;
  159.                     }
  160.                     s = s.substr(0, i+1) + ")" + s.substr(i+1, max((size_t)0, s.length() - (i+1)));
  161.                 }
  162.                 i ++;
  163.             }
  164.             i ++;
  165.         }
  166.     }
  167.  
  168. public:
  169.     static long long solve(string &expression){
  170.         /// Функція, яка рахує значення виразу у польському записі.
  171.         /// Суть проста: записуємо в стек всі числа. Коли зустрічаємо операцію, то беремо зі стеку два останніх числа, виконуємо операцію над ними, і кидаємо результат виконання у стек.
  172.         stack < long long > values;
  173.         long long tmp = -1;
  174.         for (char c: expression){
  175.             if (c == ' '){
  176.                 if (tmp > -1) values.push(tmp);
  177.                 tmp = -1;
  178.             }else{
  179.                 if (c <= '9' && c >= '0'){
  180.                     if (tmp == -1) tmp = 0;
  181.                     tmp = tmp * 10 + ((long long)(c) - (long long)('0'));
  182.                 }else{
  183.                     long long a = values.top();
  184.                     values.pop();
  185.                     long long b = values.top();
  186.                     values.pop();
  187.                     if (c == '+'){
  188.                         values.push(a+b);
  189.                     }else{
  190.                         if (c == '-'){
  191.                             values.push(b-a);
  192.                         }else{
  193.                             values.push(a*b);
  194.                         }
  195.                     }
  196.                 }
  197.             }
  198.         }
  199.         return values.top(); /// В кінці, відповідь буде єдиним числом, яке залишиться в стекові.
  200.     }
  201.  
  202.     static string convert(string &s){
  203.         /// Функція, яка конвертує звичайний запис в польський і повертає новий рядок.
  204.         place_brackets(s); /// Спершу ставимо дужки навколо всіх операцій множення.
  205.         stack < pair < string, size_t > > operations, values;
  206.         vector < string > values_tmp;
  207.         vector < char > operations_tmp;
  208.         bool can_be_processed;
  209.         operations.push({s, 0});
  210.         /**
  211.             Далі тут все відбувається схоже до того, як воно було в задачі про логічні операції:
  212.             Є два стеки. В одному зберігаються дужки, які треба перетворити, в іншому - перетворені дужки для подальшого використання.
  213.             Якщо в дужках, які зараз розглядаємо, є ще дужки, то вираз в глибших дужках кидаємо у стек невиконаних операцій, або дістаємо заміну зі стеку значень,
  214.                 якщо там є підходящі.
  215.         **/
  216.         while(!operations.empty()){
  217.             string v = operations.top().first;
  218.             size_t return_pos = operations.top().second;
  219.             size_t cur_pos = operations.size();
  220.             size_t i = 0;
  221.             string tmp = "";
  222.             can_be_processed = true;
  223.             while(i < v.length()){
  224.                 if (v[i] <= '9' && v[i] >= '0'){
  225.                     tmp += v[i];
  226.                 }else{
  227.                     if (tmp != ""){
  228.                         values_tmp.push_back(tmp);
  229.                     }
  230.                     tmp = "";
  231.                     if (v[i] == '('){
  232.                         int scope = 1;
  233.                         i ++;
  234.                         while(i < v.length()){
  235.                             if (v[i] == '(') scope ++;
  236.                             else if (v[i] == ')') scope --;
  237.                             if (scope == 0) break;
  238.                             tmp += v[i];
  239.                             i ++;
  240.                         }
  241.                         if (values.size() == 0 || values.top().second != cur_pos){
  242.                             operations.push({tmp, cur_pos});
  243.                             can_be_processed = false;
  244.                         }else{
  245.                             values_tmp.push_back(values.top().first);
  246.                             values.pop();
  247.                         }
  248.                         tmp = "";
  249.                     }else{
  250.                         operations_tmp.push_back(v[i]);
  251.                     }
  252.                 }
  253.                 i ++;
  254.             }
  255.             if (tmp != "") values_tmp.push_back(tmp);
  256.             if (can_be_processed){
  257.                 for (size_t i=0; i<operations_tmp.size(); i++){
  258.                     values_tmp[i+1] = values_tmp[i] + " " + values_tmp[i+1] + " " + operations_tmp[i];
  259.                 }
  260.                 operations.pop();
  261.                 values.push({values_tmp.back(), return_pos});
  262.             }
  263.             values_tmp.clear();
  264.             operations_tmp.clear();
  265.         }
  266.         return values.top().first;
  267.     }
  268.  
  269.     static void run(){ /// Функція для перевірки роботи класу. Приймає вираз у звичайному записі, перетворює в польський і обраховує його.
  270.         string s;
  271.         getline(cin, s);
  272.         s = Polish::convert(s);
  273.         cout << Polish::solve(s) << '\n';
  274.     }
  275. };
  276.  
  277. int main(){
  278.     Polish::run();
  279.     Parser::run();
  280.     return 0;
  281. }
  282.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement