【问题描述】
明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。
这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
1.表达式只可能包含一个变量‘a’。
2.表达式中出现的数都是正整数,而且都小于10000。
3.表达式中可以包括四种运算‘+’(加),‘-’(减),‘*’(乘),‘^’(乘幂),以及小括号‘(’,‘)’。小括号的优先级最高,其次是‘^’,然后是‘*’,最后是‘+’和‘-’。‘+’和‘-’的优先级是相同的。相同优先级的运算从左到右进行。(注意:运算符‘+’,‘-’,‘*’,‘^’以及小括号‘(’,‘)’都是英文字符)
4.幂指数只可能是1到10之间的正整数(包括1和10)。
5.表达式内部,头部或者尾部都可能有一些多余的空格。
下面是一些合理的表达式的例子:
((a^1)^2)^3,a*a+a-a,((a+a)),9999+(a-a)*a,1+(a-1)^3,1^10^9……
【样例输入】
(a+1)^2
3
(a-1)^2+4*a
a+1+a
a^2+2*a*1+1^2+10-10+a-a
【样例输出】
AC
【解题思路】
本题为NOIP2005提高组第四题,求两个表达式是否等价,其实就是看两个表达式的值是否相等,因此,我们将a换为随机化的数,多次随机化的数产生的结果都相等的话,就说明两个表达式等价,便输出表达式的选项,求表达式的值,自然就是用栈来解决,详见NOIP2013普及组第二题。我在这道题上用了两个总过程,一个建栈,一个计算
【代码实现】
1 type arr=array[1..2000] of char; 2 arr2=array[1..2000] of extended; 3 var ii,jj,n,c1,c2:longint; 4 tag:boolean; 5 x1,x2,x3:extended; 6 c:char; 7 st,a,e:string; 8 function pop(var stack:arr; var t:longint):char; 9 begin 10 pop:=stack[t]; 11 dec(t); 12 end; 13 function top(var stack:arr; var t:longint):char; 14 begin 15 top:=stack[t]; 16 end; 17 procedure push(var stack:arr; ch:char; var t:longint); 18 begin 19 inc(t); 20 stack[t]:=ch; 21 end; 22 procedure create(var x,y:string);//建栈 23 var s:arr; 24 tp,i,j,k:longint; 25 begin 26 x:=x+'@';i:=1;tp:=0;y:=''; 27 while x[i]<>'@' do 28 begin 29 case x[i] of 30 '0'..'9': 31 begin 32 while (x[i]>='0')and(x[i]<='9') do 33 begin 34 y:=y+x[i]; 35 inc(i); 36 end; 37 dec(i); 38 y:=y+'.'; 39 end; 40 'a':y:=y+'a'; 41 '(':push(s,'(',tp); 42 ')': 43 begin 44 if tp>0 then 45 begin 46 c:=top(s,tp); 47 while c<>'(' do 48 begin 49 y:=y+c; 50 c:=pop(s,tp); 51 if tp>0 then 52 c:=top(s,tp) 53 else 54 break; 55 end; 56 end; 57 if (tp>0)and(c='(')then 58 c:=pop(s,tp); 59 end; 60 '+','-': 61 begin 62 if tp>0 then 63 begin 64 c:=top(s,tp); 65 while c<>'(' do 66 begin 67 y:=y+c; 68 c:=pop(s,tp); 69 if tp>0 then 70 c:=top(s,tp) 71 else 72 break; 73 end; 74 end; 75 push(s,x[i],tp); 76 end; 77 '*','/': 78 begin 79 if tp>0 then 80 begin 81 c:=top(s,tp); 82 while (c<>'(')and(c<>'+')and(c<>'-') do 83 begin 84 y:=y+c; 85 c:=pop(s,tp); 86 if tp>0 then 87 c:=top(s,tp) 88 else 89 break; 90 end; 91 end; 92 push(s,x[i],tp); 93 end; 94 '^': 95 begin 96 if tp>0 then 97 begin 98 c:=top(s,tp); 99 while c='^' do 100 begin 101 y:=y+c; 102 c:=pop(s,tp); 103 if tp>0 then 104 c:=top(s,tp) 105 else 106 break; 107 end; 108 end; 109 push(s,x[i],tp); 110 end; 111 end; 112 inc(i); 113 end; 114 while tp>0 do 115 y:=y+pop(s,tp); 116 y:=y+'@'; 117 end; 118 function pop2(var stack:arr2;var tp:longint):extended; 119 begin 120 pop2:=stack[tp]; 121 dec(tp); 122 end; 123 function top2(var stack:arr2; var tp:longint):extended; 124 begin 125 top2:=stack[tp]; 126 end; 127 procedure push2(var stack:arr2; num:extended; var tp:longint); 128 begin 129 inc(tp); 130 stack[tp]:=num; 131 end; 132 function chu(x,y:extended):extended; 133 begin 134 if y=0 then 135 chu:=-maxlongint 136 else 137 chu:=x/y; 138 end; 139 function cf(x,y:extended):extended; 140 var i:longint; 141 begin 142 cf:=1; 143 for i:=1 to round(y) do 144 cf:=cf*x; 145 end; 146 function work(x:string;v:extended):extended;//求表达式的值 147 var s:arr2; 148 i,j,tp:longint; 149 k,w1,w2:extended; 150 begin 151 i:=1;tp:=0; 152 while x[i]<>'@' do 153 begin 154 case x[i] of 155 '0'..'9': 156 begin 157 k:=0; 158 while x[i]<>'.' do 159 begin 160 k:=k*10+ord(x[i])-48; 161 inc(i); 162 end; 163 push2(s,k,tp); 164 end; 165 'a': 166 begin 167 k:=v; 168 push2(s,k,tp); 169 end; 170 '+':push2(s,pop2(s,tp)+pop2(s,tp),tp); 171 '-': 172 begin 173 w2:=pop2(s,tp); 174 w1:=pop2(s,tp); 175 push2(s,w1-w2,tp); 176 end; 177 '*':push2(s,pop2(s,tp)*pop2(s,tp),tp); 178 '/'://可能除以0,需要判断 179 begin 180 w2:=pop2(s,tp); 181 w1:=pop2(s,tp); 182 k:=chu(w1,w2); 183 if k=-maxlongint then 184 exit(-maxlongint) 185 else 186 push2(s,k,tp); 187 end; 188 '^': 189 begin 190 w2:=pop2(s,tp); 191 w1:=pop2(s,tp); 192 push2(s,cf(w1,w2),tp); 193 end; 194 end; 195 inc(i); 196 end; 197 work:=pop2(s,tp); 198 end; 199 procedure k; 200 var st1,st2,s1,s2:string; 201 ch:char; 202 r,u:longint; 203 t1,t2:extended; 204 begin 205 readln(e); 206 while pos(chr(32),e)<>0 do 207 delete(e,pos(chr(32),e),1); 208 create(e,a); 209 tag:=true;//判断两个表达式是否相等 210 c1:=0; 211 c2:=0; 212 for jj:=1 to 20 do 213 begin 214 x3:=random; 215 x1:=work(st,x3); 216 x2:=work(a,x3); 217 if (x1=1)or(x2=1) then 218 begin 219 if abs(x1-x2)<1e-10 then 220 continue 221 else 222 begin 223 tag:=false; 224 break; 225 end; 226 end; 227 if (x1=-maxlongint)or(x2=-maxlongint) then 228 begin 229 if x1=-maxlongint then 230 inc(c1); 231 if x2=-maxlongint then 232 inc(c2); 233 continue; 234 end 235 else 236 begin 237 str(x1,st1); 238 str(x2,st2); 239 s1:=copy(st1,1,10); 240 s2:=copy(st2,1,10); 241 t1:=ln(abs(x1)); 242 t2:=ln(abs(x2)); 243 if not((x1=x2)or(((x1>0)and(x2>0)or(x1<0)and(x2<0))and(round(t1)=round(t2))and(s1=s2))) then 这里是一个很重要的判断是否相等的句子,可以自行思考一下 244 begin 245 tag:=false; 246 break; 247 end; 248 end; 249 end; 250 if (c1=0)and(c2>0)or(c1>0)and(c2=0) then 251 tag:=false; 252 if tag then 253 write(chr(ii+64)); 254 end; 255 begin 256 randomize;//随机化 257 readln(e); 258 while pos(chr(32),e)<>0 do 259 delete(e,pos(chr(32),e),1);//数据有坑,无缘无故会有许多多余的空格 260 create(e,st); 261 readln(n); 262 for ii:=1 to n do 263 begin 264 if ii=14 then 265 n:=n; 266 k; 267 end; 268 writeln; 269 end.