表达式求值

注意:这是一篇个人学习笔记,如果有人因为某些原因点了进来并且要看一下,请一定谨慎地阅读,因为可能存在各种奇怪的错误,如果有人发现错误请指出谢谢!


以前的:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 using namespace std;
 5 int lc[10000],rc[10000];
 6 int type[10000];
 7 double data[10000];
 8 char s[10000];
 9 int nc,len,p;
10 bool judge_num(int x,int y)
11 {
12     if(y-x==1&&s[x]=='-')   return false;
13     if(s[x]=='+'||s[x]=='*'||s[x]=='/'||s[x]=='^')
14         return false;
15     for(int i=x+1;i<y;i++)
16     {
17         if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/'||s[i]=='^')
18             return false;
19     }
20     return true;
21 }
22 int build(int x,int y)
23 {
24     int i,c1=-1,c2=-1,c3=-1,p=0;
25     int u;
26     if(judge_num(x,y)==true)
27     {
28         u=++nc;
29         lc[u]=rc[u]=0;
30         type[u]=0;
31         sscanf(s+x,"%lf",&data[u]);
32         return u;
33     }
34     for(i=x;i<y;i++)
35     {
36         switch(s[i])
37         {
38             case '(': p++;break;
39             case ')': p--;break;
40             case '+': case '-': if(!p) c1=i;break;
41             case '*': case '/': if(!p) c2=i;break;
42             case '^': if(!p) c3=i;break;
43         }
44     }
45     if(c1<0) c1=c2;
46     if(c1<0) c1=c3;
47     if(c1<0) return build(x+1,y-1);
48     u=++nc;
49     lc[u]=build(x,c1);
50     rc[u]=build(c1+1,y);
51     if(s[c1]=='+')  type[u]=1;
52     else if(s[c1]=='-') type[u]=2;
53     else if(s[c1]=='*') type[u]=3;
54     else if(s[c1]=='/') type[u]=4;
55     else type[u]=5;
56     return u;
57 }
58 double run(int u)
59 {
60     if(type[u]==1)  return run(lc[u])+run(rc[u]);
61     if(type[u]==2)  return run(lc[u])-run(rc[u]);
62     if(type[u]==3)  return run(lc[u])*run(rc[u]);
63     if(type[u]==4)  return run(lc[u])/run(rc[u]);
64     if(type[u]==5)  return pow(run(lc[u]),run(rc[u]));
65     return data[u];
66 }
67 int main()
68 {
69     scanf("%s",s+1);
70     len=strlen(s+1);
71     p=build(1,len+1);
72     printf("%.3lf",run(p));
73     return 0;
74 }
View Code

写了个O(n)的表达式树...实际要用可能要稍微改一下

题面:http://210.33.19.103/contest/997

中缀转后缀自然是不用的...

这里大部分的写法跟网上是一样的(就是两个栈:操作符栈,操作数栈;遇到数就加入数栈,遇到符号就while(栈顶操作符优先级>=当前的)不断弹出栈顶操作符(弹出方法:弹出操作符,以及两个栈顶操作数,做完运算后将结果放回操作数栈)),然而写的比较麻烦..写了一个"栈套栈",遇到左括号就新建一层栈,遇到右括号就做完当前层栈留下的运算符,将栈的层数减1,并把剩下的唯一一个数放入上一层栈

  1 //#pragma GCC optimize(3)
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<vector>
  6 using namespace std;
  7 #define fi first
  8 #define se second
  9 #define mp make_pair
 10 #define pb push_back
 11 typedef long long ll;
 12 typedef unsigned long long ull;
 13  
 14 int n,md;
 15 char ss[5001000];
 16  
 17 void do_ub(int x)
 18 {
 19     if(!x)
 20     {
 21         printf("failed:%d\n",x);
 22         int *a=0;*a=234;
 23     }
 24 }
 25 #define assert(x) do_ub(x)
 26  
 27 struct Nd
 28 {
 29     int d;
 30     int type;//0:数字;1:+;2:-;3:*;4:/;5:(;6:)
 31     int num;
 32 };
 33 Nd pre[5001000];
 34 int inv[500100];
 35 int left,plen;
 36 int order[]={3,1,1,2,2};
 37 bool isdigit1(char x){return x>='0'&&x<='9';}
 38 int ma[666];
 39  
 40 int an[5001000];
 41 struct TNd
 42 {
 43     int ch[2];
 44     int type;
 45     int d,num;
 46 }nn[5001000];
 47 int mem;
 48 struct ST
 49 {
 50     int st1[10001000],st2[10001000],tp1,tp2;
 51     ST()
 52     {
 53         tp1=0;tp2=1;st2[1]=0;
 54     }
 55     void push(int x)
 56     {
 57         st1[++tp1]=x;
 58     }
 59     bool empty()
 60     {
 61         assert(tp1>=st2[tp2]);
 62         return tp1==st2[tp2];
 63     }
 64     void pop()
 65     {
 66         assert(tp1>st2[tp2]);
 67         if(tp1>st2[tp2]) --tp1;
 68     }
 69     int top()
 70     {
 71         assert(tp1>st2[tp2]);
 72         return st1[tp1];
 73         //return tp1>st2[tp2]?st1[tp1]:0;
 74     }
 75     void add_stack()
 76     {
 77         st2[++tp2]=tp1;
 78     }
 79     void del_stack()
 80     {
 81         assert(tp1==st2[tp2]);
 82         --tp2;
 83     }
 84 }st1,st2;
 85 int calc(int a,int b,int c)
 86 {
 87     if(a==-1||b==-1)    return -1;
 88     switch(c)
 89     {
 90     case 1:
 91         return (a+b)%md;
 92     case 2:
 93         return (a-b+md)%md;
 94     case 3:
 95         return ll(a)*b%md;
 96     case 4:
 97         if(b==0)    return -1;
 98         return ll(a)*inv[b]%md;
 99     default:
100         assert(0);
101         return 0;
102     }
103 }
104 void pop1()
105 {
106     int t1,t2,t3,t;
107     t3=st2.top();st2.pop();
108     t2=st1.top();st1.pop();
109     if(st1.empty())
110     {
111         assert(t3==1||t3==2);
112         t1=0;
113     }
114     else
115     {
116         t1=st1.top();st1.pop();
117     }
118     t=++mem;
119     nn[t].type=t3;
120     nn[t].d=calc(nn[t1].d,nn[t2].d,t3);
121     nn[t].ch[0]=t1;nn[t].ch[1]=t2;
122     st1.push(t);
123 }
124 int len;
125 int calc_r1(int a,int b,int c)//找出x使得a c x = b
126 {
127     if(a==-2||b==-2)    return -2;
128     if(a==-1||b==-1)    return -1;
129     switch(c)
130     {
131     case 1:
132         return calc(b,a,2);
133     case 2:
134         return calc(a,b,2);
135     case 3:
136         if(a==0)    return b==0?-1:-2;
137         return calc(b,a,4);
138     case 4:
139         if(a==0)    return b==0?-1:-2;
140         if(b==0)    return a==0?-1:-2;
141         return calc(a,b,4);
142     default:
143         assert(0);
144         return 0;
145     }
146 }
147 int calc_r2(int a,int b,int c)//找出x使得x c a = b
148 {
149     if(a==-2||b==-2)    return -2;
150     if(a==-1||b==-1)    return -1;
151     switch(c)
152     {
153     case 1:
154         return calc(b,a,2);
155     case 2:
156         return calc(b,a,1);
157     case 3:
158         if(a==0)    return b==0?-1:-2;
159         return calc(b,a,4);
160     case 4:
161         if(a==0)    return -2;
162         return calc(a,b,3);
163     default:
164         assert(0);
165         return 0;
166     }
167 }
168 void solve(int rt,int x)//x为要使得子树成为的值,-1->-1,-2->无解
169 {
170     //printf("t%d %d\n",rt,x);
171     if(nn[rt].type==0)  an[nn[rt].num]=x;
172     else if(!nn[rt].ch[0])  solve(nn[rt].ch[1],calc_r1(0,x,nn[rt].type));
173     else if(!nn[rt].ch[1])  assert(0);//solve(ch[0],x);
174     else
175     {
176         //if(x<0)
177         //printf("%d ch1 %d\n",rt,nn[nn[rt].ch[1]].d);
178         solve(nn[rt].ch[0],calc_r2(nn[nn[rt].ch[1]].d,x,nn[rt].type));
179         //printf("%d ch0 %d\n",rt,nn[nn[rt].ch[0]].d);
180         solve(nn[rt].ch[1],calc_r1(nn[nn[rt].ch[0]].d,x,nn[rt].type));
181     }
182 }
183 int rt;
184 int main()
185 {
186     bool fl=0;
187     int i,edpos=0,nowd,nowdep,t1;
188     ma['+']=1;ma['-']=2;ma['*']=3;ma['/']=4;ma['(']=5;ma[')']=6;
189     scanf("%d%d",&n,&md);
190     inv[1]=1;
191     for(i=2;i<md;i++)    inv[i]=ll(md-md/i)*inv[md%i]%md;
192     scanf("%s",ss+1);len=strlen(ss+1);
193     for(i=1;i<=len;i++)
194     {
195         if(isdigit1(ss[i]))
196         {
197             edpos=i;
198             left=left*10+ss[i]-'0';
199         }
200         else
201             break;
202     }
203     nowd=nowdep=0;
204     for(i=edpos+2;i<=len;i++)
205     {
206         if(isdigit1(ss[i]))
207         {
208             fl=1;
209             nowd=nowd*10+ss[i]-'0';
210         }
211         else
212         {
213             if(fl)
214             {
215                 fl=0;
216                 ++plen;
217                 pre[plen].d=nowd;pre[plen].type=0;
218                 nowd=0;
219             }
220             ++plen;
221             pre[plen].type=ma[ss[i]];
222         }
223     }
224     if(fl)
225     {
226         ++plen;
227         pre[plen].d=nowd;pre[plen].type=0;
228     }
229     for(i=1;i<=plen;i++)
230     {
231         if(pre[i].type==0&&pre[i].num!=-1)
232         {
233             pre[i].num=++mem;
234             nn[mem].type=0;nn[mem].d=pre[i].d;nn[mem].num=i;
235         }
236     }
237     for(i=1;i<=plen;i++)
238     {
239         if(pre[i].type==5)
240         {
241             st1.add_stack();st2.add_stack();
242         }
243         else if(pre[i].type==6)
244         {
245             while(!st2.empty()) pop1();
246             t1=st1.top();st1.pop();
247             st1.del_stack();st2.del_stack();
248             st1.push(t1);
249         }
250         else if(pre[i].type==0)
251         {
252             st1.push(pre[i].num);
253         }
254         else
255         {
256             while(!st2.empty()&&order[st2.top()]>=order[pre[i].type])
257                 pop1();
258             st2.push(pre[i].type);
259         }
260     }
261     while(!st2.empty())pop1();//{printf("tt%d\n",st2.top());st2.pop();}
262     //while(!st1.empty()){printf("2t%d\n",st1.top());st1.pop();}
263     rt=st1.top();st1.pop();
264     /*
265     for(i=1;i<=mem;i++)
266     {
267         printf("%d %d ",i,nn[i].type);
268         if(nn[i].type==0)   printf("%d ",nn[i].d);
269         else printf("%d %d ",nn[i].ch[0],nn[i].ch[1]);
270         printf("%d ",nn[i].d);
271         puts("");
272     }
273     */
274     solve(rt,left);
275     for(i=1;i<=plen;i++)
276         if(pre[i].type==0)
277         {
278             if(an[i]==-2)   puts("No Solution");
279             else    printf("%d\n",an[i]);
280         }
281     return 0;
282 }
View Code

事实上并不要的...只要把左括号放进栈,然后每一次做运算时保证不弹栈顶左括号(由于前置的-/+,可能弹不出来数,弹不出来了就弹0)

搞不清楚,还是前面那样写了..反正只是多点代码量,写写很快的

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 #include<cmath>
  6 using namespace std;
  7 #define fi first
  8 #define se second
  9 #define mp make_pair
 10 #define pb push_back
 11 typedef long long ll;
 12 typedef unsigned long long ull;
 13 typedef pair<int,int> pii;
 14 template<class T>
 15 struct mstack
 16 {
 17     T d1[1001000];
 18     size_t d2[1001000],tp1,tp2;
 19     mstack():tp1(0),tp2(1){d2[1]=0;}
 20     bool empty(){return tp1==d2[tp2];}
 21     T top(){return empty()?0:d1[tp1];}
 22     void pop(){if(!empty())--tp1;}
 23     void push(const T &x){d1[++tp1]=x;}
 24     void del_stack(){--tp2;}
 25     void add_stack(){d2[++tp2]=tp1;}
 26 };
 27 mstack<double> st1;
 28 mstack<char> st2;
 29 int od[2333];
 30 double calc(double a,double b,char c)
 31 {
 32     //printf("tt%f %f %c\n",a,b,c);
 33     switch(c)
 34     {
 35     case '+':
 36         return a+b;
 37     case '-':
 38         return a-b;
 39     case '*':
 40         return a*b;
 41     case '/':
 42         return a/b;
 43     case '^':
 44         return pow(a,b);
 45     default:
 46         return 233;
 47     }
 48 }
 49 char s[1001000];
 50 int len;
 51 bool ok(char a,char b)//x a y b z是否先运算a
 52 {
 53     if(a=='^'&&b=='^')  return 0;
 54     return od[a]>=od[b];
 55 }
 56 int main()
 57 {
 58     int i,tlen;double a,b,tt;char c;
 59     od['+']=od['-']=1;od['*']=od['/']=2;od['^']=3;
 60     scanf("%s",s);len=strlen(s);
 61     for(i=0;i<len;)
 62     {
 63         //printf("ttt%d\n",i);
 64         switch(s[i])
 65         {
 66         case '(':
 67             st1.add_stack();st2.add_stack();
 68             i++;
 69             break;
 70         case '+':
 71         case '-':
 72         case '*':
 73         case '/':
 74         case '^':
 75             while(!st2.empty()&&ok(st2.top(),s[i]))
 76             {
 77                 c=st2.top();st2.pop();
 78                 b=st1.top();st1.pop();
 79                 a=st1.top();st1.pop();
 80                 st1.push(calc(a,b,c));
 81             }
 82             st2.push(s[i]);
 83             i++;
 84             break;
 85         case ')':
 86             while(!st2.empty())
 87             {
 88                 c=st2.top();st2.pop();
 89                 b=st1.top();st1.pop();
 90                 a=st1.top();st1.pop();
 91                 st1.push(calc(a,b,c));
 92             }
 93             a=st1.top();st1.pop();
 94             st1.del_stack();st2.del_stack();
 95             st1.push(a);
 96             i++;
 97             break;
 98         default:
 99             sscanf(s+i,"%lf%n",&tt,&tlen);
100             st1.push(tt);
101             i+=tlen;
102         }
103     }
104     while(!st2.empty())
105     {
106         c=st2.top();st2.pop();
107         b=st1.top();st1.pop();
108         a=st1.top();st1.pop();
109         st1.push(calc(a,b,c));
110     }
111     printf("%.2f",st1.top());
112     return 0;
113 }
View Code

可以用sscanf直接读数字,用%n获取读取过程中消耗的字符数

 

posted @ 2018-09-14 14:34  hehe_54321  阅读(165)  评论(0编辑  收藏  举报
AmazingCounters.com