题意:有5个数,3种运算符:加、减、乘,用全部5个数,和4个运算符,构成一个表达式,使得值为23,这里没有运算符的优先级,全部是从左往右算。是可以这么理解,题目给的是从左到右依次打了括号。
思路:这里是对表达式的位置进行dfs。可以看到第0位是数字,第1位是运算符,依次则,偶数位是数字,奇数位是运算符。dfs中把当前位置cur分为奇偶分别处理。偶数位置时,则对数字进行枚举,并计算当前表达式的值,注意dfs之后的恢复;奇数位置时,枚举三种运算符。对比可以发现,枚举数字时,由于数字只能出现一次,所以用vis数组标志是否用过;枚举运算符时,由于运算符可多次使用,所以直接枚举即可。另外,初次的dfs调用,由于a[0]前面没有运算符,可默认其为+号,所以初次以dfs(0,‘+‘,0)调用。
还有一种方法是,对每种排列枚举运算符进行运算即可。即调用next_permutation。这里没写。我这里的方法相当于把数字和运算符混在一起进行排列。
解答树的结点个数也可以计算,5!*3^4=9720。测试后发现如果不剪枝,时间有点长。。
注意:开始的思路是在遇到运算符时进行表达式的计算,但这样如果以dfs(0,0,0)初次调用的话,则在a[0]前面也枚举了运算符,是不对的;之后把这一点改了。改成的版本,在1号位没有用,0号和2号位是数字,然后3号位枚举符号,是运算0号和2号的数字的。相当于了后缀表达式形式了。但还是有问题。。。附在最后。
这说明,开始写之前,还是要多想想;否则写出来一个挫的之后,这里发现一问题,那里发现一问题,在它的基础上缝缝补补,就把自己搞得晕头转向了,有时甚至还不如重头重新写,比如这里就是暂时放下了,重新写的,很快就好了。
这里给出一些测试数据:
input:
42 8 2 32 37
10 43 21 46 5
44 2 27 30 29
10 20 20 2 36
28 3 34 42 2
22 6 6 5 37
34 3 31 18 12
25 46 28 13 2
12 4 19 2 50
1 12 2 1 49
48 48 42 2 11
1 2 43 26 33
0 0 0 0 0
output:
Possible
Possible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible
Code:
//AC了 #include<stdio.h> #include<string.h> bool dfs(int cur,char c,int cnt); int a[6]; int vis[6]; //int C[15]; //char F[5]; int main() { while(scanf("%d%d%d%d%d",&a[0],&a[1],&a[2],&a[3],&a[4])==5 &&a[0]&&a[1]&&a[2]&&a[3]&&a[4]) { memset(vis,0,sizeof(vis)); if(dfs(0,'+',0)) printf("Possible\n"); else printf("Impossible\n"); } return 0; } bool dfs(int cur,char c,int cnt) { if(cur==9) { if(cnt==23) { return 1; } else return 0; } if(cur%2==0) {//枚举数字 for(int i=0;i<5;++i) if(!vis[i]) { vis[i]=1;//选择a[i] if(c=='+') cnt=cnt+a[i]; else if(c=='-') cnt=cnt-a[i]; else cnt=cnt*a[i]; if(dfs(cur+1,' ',cnt)) return 1; vis[i]=0; if(c=='+') cnt=cnt-a[i]; else if(c=='-') cnt=cnt+a[i]; else cnt=cnt/a[i]; } } else {//枚举运算符 if(dfs(cur+1,'+',cnt)) return 1; if(dfs(cur+1,'-',cnt)) return 1; if(dfs(cur+1,'*',cnt)) return 1; } return 0; }AC之后的时间是2.942s,限制是在3s内,这是擦边过啊。于是写了一个剪枝的,时间减少一半多,但还是1.275s,排在1318名。
Code:
//AC了,在上一版本上的剪枝 #include<stdio.h> #include<string.h> bool dfs(int cur,char c,int cnt); int a[6]; int vis[6]; //int C[15]; //char F[5]; int main() { while(scanf("%d%d%d%d%d",&a[0],&a[1],&a[2],&a[3],&a[4])==5 &&a[0]&&a[1]&&a[2]&&a[3]&&a[4]) { memset(vis,0,sizeof(vis)); if(dfs(0,'+',0)) printf("Possible\n"); else printf("Impossible\n"); } return 0; } bool dfs(int cur,char c,int cnt) { int temps=0; for(int i=0;i<5;++i) if(!vis[i]) temps=temps+a[i]; if(cnt-temps>23) return 0; //剪枝 if(cnt<0 && cnt+temps<23) return 0; if(cur==9) { if(cnt==23) { return 1; } else return 0; } if(cur%2==0) {//枚举数字 for(int i=0;i<5;++i) if(!vis[i]) { vis[i]=1;//选择a[i] if(c=='+') cnt=cnt+a[i]; else if(c=='-') cnt=cnt-a[i]; else cnt=cnt*a[i]; if(dfs(cur+1,' ',cnt)) return 1; vis[i]=0; if(c=='+') cnt=cnt-a[i]; else if(c=='-') cnt=cnt+a[i]; else cnt=cnt/a[i]; } } else {//枚举运算符 if(dfs(cur+1,'+',cnt)) return 1; if(dfs(cur+1,'-',cnt)) return 1; if(dfs(cur+1,'*',cnt)) return 1; } return 0; }最初始的思路,没AC,有问题的Code:
//有问题 //思路是在主函数中枚举第0位的数字。dfs函数中忽略1号位,从2号位开始偶数位枚举数字, //奇数位枚举运算符。3号位的运算符是计算0号和2号的数字的,相当于了后缀表达式形式。 //但还没有AC,还是有些问题~ #include<stdio.h> #include<string.h> bool dfs(int cur,int pre,int cnt); int a[6]; int vis[6]; int C[15]; char F[5]; int main() { while(scanf("%d%d%d%d%d",&a[0],&a[1],&a[2],&a[3],&a[4])==5 &&a[0]&&a[1]&&a[2]&&a[3]&&a[4]) { //if(dfs(0,0,0)) printf("Possible\n");else printf("Impossible\n"); int flag=0; for(int i=0;i<4;++i) { memset(vis,0,sizeof(vis)); int cnt=a[i]; vis[i]=1; C[0]=a[i]; if(flag=dfs(1,0,cnt)) break; } if(flag) printf("Possible\n"); else printf("Impossible\n"); } return 0; } bool dfs(int cur,int pre,int cnt) { if(cur==10) { if(cnt==23) { for(int i=0;i<4;++i) printf("%d%c",C[i],F[i+1]); printf("%d\n",C[4]); return 1; } else return 0; } if(cur%2==0) {//枚举数字 for(int i=0;i<5;++i) if(!vis[i]) { vis[i]=1;//选择a[i] C[cur/2]=a[i]; if(dfs(cur+1,a[i],cnt)) return 1; vis[i]=0; } } else {//枚举运算符 if(cur==1) dfs(cur+1,0,cnt); for(int i=0;i<3;++i) { if(i==0) { cnt=cnt+pre; F[cur/2]='+'; if(dfs(cur+1,0,cnt)) return 1; cnt=cnt-pre;} else if(i==1) { cnt=cnt-pre; F[cur/2]='-'; if(dfs(cur+1,0,cnt)) return 1; cnt=cnt+pre;} else { cnt=cnt*pre; F[cur/2]='*'; if(dfs(cur+1,0,cnt)) return 1; cnt=cnt/pre;} } } return 0; }
原文地址:http://blog.csdn.net/buxizhizhou530/article/details/44042941