中缀表达式、后缀表达式、调度场算法、表达式树



前言

终于抽出时间更新了 QAQ
忘了今年哪场网络赛,有道Call of Accepted,通过人数很多,队友说去看看那个?我说不了不了,虽然我知道是水题,但是那个算法我不会啊!
终究欠的总是要还的 _(:з」∠)_

  1. 后缀表达式
    https://blog.csdn.net/Antineutrino/article/details/6763722
    https://liam0205.me/2016/12/14/Shunting-Yard-Algorithm/
    https://blog.csdn.net/walkerkalr/article/details/22798365
  2. 表达式树
    https://blog.csdn.net/buaa_shang/article/details/9124075

简单计算器 - HDU - 1237


思路
模板题(而且还没括号 = =||)

  #include <iostream>
  #include <cstdio>
  #include <cstring>
  #include <cctype>
  #include <stack>
  const int N = 200 + 5;
  using namespace std;

  struct Data{
      int data, type;
  };

  char s[N];
  Data suffix_exp[N];
  int  pp;

  int getPriority(char a){
      if(a == '*' || a == '/')           return 2;
      else if(a == '+' || a == '-')      return 1;
      else                               return 0;
  }

  void getSuffixExp(char s[]){
      pp = 0;
      stack<char> stk;
      for(int i = 0; s[i]; ){
          if(s[i] == ' '){
              i++;
              continue;
          }

          if(isdigit(s[i])){
              sscanf(s + i, "%d", &suffix_exp[pp].data);
              suffix_exp[pp++].type = 0;
              while(isdigit(s[i]))    i++;
          }else{
              while(!stk.empty() && getPriority(stk.top()) >= getPriority(s[i])){
                  suffix_exp[pp++] = Data{stk.top(), 1};
                  stk.pop();
              }

              stk.push(s[i]);
              i++;
          }
      }
      while(!stk.empty()){
          suffix_exp[pp++] = Data{stk.top(), 1};
          stk.pop();
      }
  }

  double solve(){
      stack<double> ans;
      for(int i = 0; i < pp; i++){
          if(suffix_exp[i].type == 0)     ans.push(suffix_exp[i].data);
          else{
              double t2 = ans.top();
              ans.pop();
              double t1 = ans.top();
              ans.pop();

              if(suffix_exp[i].data == '+')        ans.push(t1 + t2);
              else if(suffix_exp[i].data == '-')   ans.push(t1 - t2);
              else if(suffix_exp[i].data == '*')   ans.push(t1 * t2);
              else if(suffix_exp[i].data == '/')   ans.push(t1 / t2);
          }
      }
      return ans.top();
  }

  int main(){
      while(true){
          gets(s);
          if(strlen(s) == 1 && s[0] == '0')   break;

          getSuffixExp(s);
          printf("%.2f\n", solve());
      }
  }


Call of Accepted - ACM-ICPC 2018 沈阳赛区网络预赛


题意
给定表达式求最大值与最小值,其中xdy表示可以取 [x, x * y] 中的数,并且d是右结合的,且运算优先级比 +-* 高
思路
需要对调度场算法进行改造
因为d是右结合的,故遇到栈顶为d时,不能立即将其弹出,而应继续入栈
剩下部分同调度场算法
最后是解决最大值最小值的问题,因为视作区间进行运算,’+’的范围则是小+小,大+大,’-‘的范围是大-小,小-大,’*‘的范围较难确定,但可以确定必然是端点之间乘出来的,所以枚举结果sort一下即可

  #include <iostream>
  #include <cstdio>
  #include <cstring>
  #include <cctype>
  #include <stack>
  #include <algorithm>
  const int N = 100 + 5;
  using namespace std;
  typedef long long ll;

  struct Data{
      ll data;
      int type;
  };

  struct Num{
      ll l, r;
  };

  char s[N];
  Data suffix_exp[N];
  int  pp;

  int getPriority(char a){
      if(a == 'd')                       return 3;
      else if(a == '*' || a == '/')      return 2;
      else if(a == '+' || a == '-')      return 1;
      else                               return 0;
  }

  void getSuffixExp(char s[]){
      pp = 0;
      stack<char> stk;
      for(int i = 0; s[i]; ){
          if(isdigit(s[i])){
              sscanf(s + i, "%lld", &suffix_exp[pp].data);
              suffix_exp[pp++].type = 0;
              while(isdigit(s[i]))    i++;
          }else{
              if(s[i] == ')'){
                  while(stk.top() != '('){
                      suffix_exp[pp++] = Data{stk.top(), 1};
                      stk.pop();
                  }
                  stk.pop();
              }else{
                  while(s[i] != 'd' && s[i] != '(' && !stk.empty() && getPriority(stk.top()) >= getPriority(s[i])){
                      suffix_exp[pp++] = Data{stk.top(), 1};
                      stk.pop();
                  }

                  stk.push(s[i]);
              }

              i++;
          }
      }
      while(!stk.empty()){
          suffix_exp[pp++] = Data{stk.top(), 1};
          stk.pop();
      }
  }

  void solve(ll& ansmin, ll& ansmax){
      stack<Num> stk;
      for(int i = 0; i < pp; i++){
          if(suffix_exp[i].type == 0){
              stk.push(Num{suffix_exp[i].data, suffix_exp[i].data});
          }else{
              Num t2 = stk.top();
              stk.pop();
              Num t1 = stk.top();
              stk.pop();

              if(suffix_exp[i].data == '+')                   stk.push(Num{t1.l + t2.l, t1.r + t2.r});
              else if(suffix_exp[i].data == '-')              stk.push(Num{t1.l - t2.r, t1.r - t2.l});
              else if(suffix_exp[i].data == '*'){
                  ll choice[4] = {t1.l * t2.l, t1.l * t2.r, t1.r * t2.l, t1.r * t2.r};
                  sort(choice, choice + 4);
                  stk.push(Num{choice[0], choice[3]});
              }else if(suffix_exp[i].data == 'd'){
                  stk.push(Num{t1.l, t1.r * t2.r});
              }
          }
      }

      ansmin = stk.top().l, ansmax = stk.top().r;
  }

  int main(){
      while(cin >> s){
          ll ansmin, ansmax;
          getSuffixExp(s);
          solve(ansmin, ansmax);

          cout << ansmin << " " << ansmax << endl;
      }
  }


Complicated Expressions - POJ - 1400


题意
对一个表达式,去除其冗余的括号
思路
先将其转为后缀表达式,再建表达式树,最后中序遍历输出
注意输出的时候判定是否需要加括号
① 如果中间的符号比其中一边的优先级大,那么该边需要加括号
② 如果中间的符号与右边的优先级相同,并且中间的符号为’/’或’-‘,那么需要加括号(因为没有结合律)

  #include <iostream>
  #include <cstdio>
  #include <cstring>
  #include <cctype>
  #include <stack>
  #include <algorithm>
  using namespace std;
  const int N = 250 + 5;
  typedef long long ll;
  const int inf = 0x3f3f3f3f;
  typedef pair<int, int> pii;

  struct ExpressionTree{
      char data;
      int  ch[2];
  };
  ExpressionTree tree[N];
  pii  suffix_exp[N];
  char s[N];
  int  pp;

  int  getPriority(char ch){
      if(ch == '*' || ch == '/')          return 2;
      else if(ch == '+' || ch == '-')     return 1;
      else                                return 0;
  }

  bool isOperation(char ch){
      return (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')');
  }

  void getSuffixExp(char s[]){
      stack<char> stk;
      pp = 0;
      for(int i = 0; s[i]; i++){
          if(isOperation(s[i])){
              if(s[i] == ')'){
                  while(!stk.empty() && stk.top() != '('){
                      suffix_exp[pp++] = make_pair(stk.top(), 1);
                      stk.pop();
                  }
                  stk.pop();
              }else{
                  while(s[i] != '(' && !stk.empty() && getPriority(stk.top()) >= getPriority(s[i])){   //)
                      suffix_exp[pp++] = make_pair(stk.top(), 1);
                      stk.pop();
                  }
                  stk.push(s[i]);
              }
          }else{
              suffix_exp[pp++] = make_pair(s[i], 0);
          }
      }
      while(!stk.empty()){
          suffix_exp[pp++] = make_pair(stk.top(), 1);
          stk.pop();
      }
  }

  void newNode(int rt, char val){
      tree[rt].ch[0] = tree[rt].ch[1] = 0;
      tree[rt].data = val;
  }

  int buildTree(){
      int rt = 0;
      stack<int> stk;
      for(int i = 0; i < pp; i++){
          if(suffix_exp[i].second == 0){
              newNode(++rt, suffix_exp[i].first);
              stk.push(rt);
          }else{
              int t2 = stk.top();
              stk.pop();
              int t1 = stk.top();
              stk.pop();

              newNode(++rt, suffix_exp[i].first);
              tree[rt].ch[0] = t1;
              tree[rt].ch[1] = t2;
              stk.push(rt);
          }
      }
      return rt;
  }

  void dfs(int u, int pre, bool is_left){
      if(!isOperation(tree[u].data)){
          putchar(tree[u].data);
          return;
      }

      bool flag = false;
      if(pre != -1 && is_left && getPriority(tree[u].data) < getPriority(tree[pre].data))                 flag = true;
      if(pre != -1 && !is_left){
          if(getPriority(tree[u].data) < getPriority(tree[pre].data))                                     flag = true;
          else if(getPriority(tree[u].data) == getPriority(tree[pre].data) && (tree[pre].data == '-' || tree[pre].data == '/'))       flag = true;
      }

      if(flag)    putchar('(');
      dfs(tree[u].ch[0], u, true);
      putchar(tree[u].data);
      dfs(tree[u].ch[1], u, false);
      if(flag)    putchar(')');
  }

  int main(){
      int t;
      scanf("%d", &t);
      getchar();
      while(t--){
          gets(s);

          getSuffixExp(s);
          int rt = buildTree();
          dfs(rt, -1, 0);
          puts("");
      }
  }