传送门 好的乱搞题一道。 先用栈处理出每个左或右括号对应的另一个右或左括号的下标。 然后求每个运算符的优先级。 具体是这样的: (1)定义一个临时变量j,表示当前位置的优先级,然后遍历表达式,初始j为1。 (2)进入一个括号j加2。(即遇到左括号) (3)+和-的优先级直接赋j。 (4)*和/的优先级赋j+1。 (5)退出一个括号j减2。(即遇到右括号) 当然我们要特判掉((sth))的情况,只要加2就ok辣。 预处理所有的优先级之后,就可以去括号了。 从1开始dfs。(当然为了方便处理,我们在原串两边加上一对括号。1号位置是那个左括号。) 每次dfs,先遍历串,处理之后的括号,保证正确性,同时还可以得到右括号的位置。 然后获取这两个括号左右位置的运算符的优先级,取最大的。 看括号内部是否有+或-号,这个不是直接看字符串,而是用优先级的大小关系判断。 如果有,那么不能去掉当前括号,返回。 如果没有,那么可以去掉,然后变号。 变号时,如果前面是减号,那么+变-,-变+。 如果前面是除号,那么变/,/变。 码量略大。
#include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 305 using namespace std; int n,a[N],le[N],ri[N],sta[N],top,T; char s[N]; int dfs(int l){ int r; for (r=l+1;s[r]!=')';r++) if (s[r]=='(') r=dfs(r); int k=max(a[l-1],a[r+1]),pos; for (pos=l+1;pos<r;pos++) if (a[pos]==k+1) break; if (pos<r) return r; s[l]=s[r]='$'; int cnt=0; if (s[l-1]=='-') for (int i=l+1;i<r;i++){ if (s[i]=='(') cnt++; else if (s[i]==')') cnt--; if (!cnt) if (s[i]=='-') s[i]='+'; else if (s[i]=='+') s[i]='-'; } if (s[l-1]=='/') for (int i=l+1;i<r;i++){ if (s[i]=='(') cnt++; else if (s[i]==')') cnt--; if (!cnt) if (s[i]=='*') s[i]='/'; else if (s[i]=='/') s[i]='*'; } return r; } void solve(){ memset(a,0,sizeof(a)); scanf("%s",s+2); n=strlen(s+2); s[1]='('; s[n+2]=')'; top=0; for (int i=1;i<=n;i++) if (s[i]=='(') sta[++top]=i; else if (s[i]==')'){ ri[sta[top]]=i; le[i]=sta[top]; top--; } a[0]=a[n+1]=1; for (int i=1,j=1;i<=n;i++) if (s[i]=='('&&(s[i-1]!='('||s[ri[i]+1]!=')')) j+=2; else if (s[i]==')'&&(s[i+1]!=')'||s[le[i]-1]!='(')) j-=2; else if (s[i]=='+'||s[i]=='-') a[i]=j; else if (s[i]=='*'||s[i]=='/') a[i]=j+1; dfs(1); for (int i=2;i<=n+1;i++) if (s[i]!='$') putchar(s[i]); puts(""); } int main(){ scanf("%d",&T); while (T--) solve(); }