【题目链接】
一开始按照判断括号是否可以去掉的方法写,对着数据调了无数个小时,也就只过了一个点。
后来问Claris(%%%%)要了代码,发现原来还可以这么搞。
先用栈处理出每个左或右括号对应的另一个右或左括号的下标。
然后求每个运算符的优先级。
具体是这样的:
(1)定义一个临时变量j,表示当前位置的优先级,然后遍历表达式,初始j为1。
(2)进入一个括号j加2。(即遇到左括号)
(3)+和-的优先级直接赋j。
(4)*和/的优先级赋j+1。
(5)退出一个括号j减2。(即遇到右括号)
有一点要注意就是遇到 ((sth)) 这种情况,这种情况下优先级只加一次2,而不是加4。这种情况的判断是用预处理出来的括号位置搞的,不懂看代码就懂了。
预处理所有的优先级之后,就可以去括号了。
从1开始dfs。(1这个位置本来是不一定有括号的,我们要人为的给表达式两边再加一对括号,这样1这个位置就有括号了,方便处理)
每次dfs,先遍历串,处理之后的括号,保证正确性,同时还可以得到右括号的位置。
然后获取这两个括号左右位置的运算符的优先级,取最大的。
看括号内部是否有+或-号,这个不是直接看字符串,而是用优先级的大小关系判断。
如果有,那么不能去掉当前括号,返回。
如果没有,那么可以去掉,然后变号。
变号时,如果前面是减号,那么+变-,-变+。
如果前面是除号,那么*变/,/变*。
看代码吧。
%一发Claris
/* Pigonometry */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 305; int n, pri[maxn], lbra[maxn], rket[maxn]; char str[maxn]; int sta[maxn]; inline int dfs(int l) { int r; for(r = l + 1; str[r] != ')'; r++) if(str[r] == '(') r = dfs(r); int k = max(pri[l - 1], pri[r + 1]), pos; for(pos = l + 1; pos < r; pos++) if(pri[pos] == k + 1) break; if(pos < r) return r; str[l] = str[r] = '$'; int cnt = 0; if(str[l - 1] == '-') for(int i = l + 1; i < r; i++) { if(str[i] == '(') cnt++; else if(str[i] == ')') cnt--; if(!cnt) if(str[i] == '-') str[i] = '+'; else if(str[i] == '+') str[i] = '-'; } if(str[l - 1] == '/') for(int i = l + 1; i < r; i++) { if(str[i] == '(') cnt++; else if(str[i] == ')') cnt--; if(!cnt) if(str[i] == '*') str[i] = '/'; else if(str[i] == '/') str[i] = '*'; } return r; } inline void solve() { memset(pri, 0, sizeof(pri)); scanf("%s", str + 2); n = strlen(str + 2); str[1] = '('; str[n + 2] = ')'; int top = 0; for(int i = 1; i <= n; i++) if(str[i] == '(') sta[++top] = i; else if(str[i] == ')') rket[sta[top]] = i, lbra[i] = sta[top--]; pri[0] = pri[n + 1] = 1; for(int i = 1, j = 1; i <= n; i++) if(str[i] == '(' && (str[i - 1] != '(' || str[rket[i] + 1] != ')')) j += 2; else if(str[i] == ')' && (str[i + 1] != ')' || str[lbra[i] - 1] != '(')) j -= 2; else if(str[i] == '+' || str[i] == '-') pri[i] = j; else if(str[i] == '*' || str[i] == '/') pri[i] = j + 1; dfs(1); for(int i = 2; i <= n + 1; i++) if(str[i] != '$') printf("%c", str[i]); printf("\n"); } int main() { int T; scanf("%d", &T); while(T--) solve(); return 0; }