算23 [EOlymp – 1540]题解
给5个数字,判断这5人数通过加减乘法运算后能否算出23
解法很多,数据量不是特别大,所以直接搜索解空间(生成数组的全排列,然后遍历所有的运算)也能正确解答。
使用递归解决:给出了5个数,假设它的某个排列是[x1,x2,x3,x4,x5],要判断用这5个数计算23,只需要判断用[x1,x2,x3,x4]能否计算出23-x5,或能否算出23+x5,或者在23被x5整除的情况下能否算出23/x5(这分别代表[..]+5=23,[..]-5=23与[..]×5=23),这样问题的规模就减小到4个数。
再递归的做下去:用[x1,x2,x3]能否算出(23-x5)-x1,或者能否算出(23-x5)+x1,或是(23-x5)被x1整除的情况下能否算出(23-x5)/x1…最后当数组规模只剩1的时候,直接判断要计算的目标是不是数组里的这个数字即可,并且对初始的5个数的所有排列形式都分别递归。只要有任何一个递归函数最终达到了[x1]==计算目标,就返回true,将所有递归结果用“逻辑或”相连接。
#include <cstdio> void swap(int *x,int *y) { if(*x!=*y) { *x^=*y; *y^=*x; *x^=*y; } } int f(int target,int *a,int N) { int i,j; if(N==1) return a[0]==target; int *b; bool pr,mr,tr=false; b=new int [N]; for(i=0;i<N;i++) { for(j=0;j<i;j++) b[j]=a[j]; for(j=i+1;j<N;j++) b[j-1]=a[j]; pr=f(target-a[i],b,N-1); mr=f(target+a[i],b,N-1); if(target%a[i]==0) tr=f(target/a[i],b,N-1); if(pr||mr||tr) break; } delete [] b; return pr||mr||tr; } int main(void) { int i,a[5]; bool bf; while(1) { bf=true; for(i=0;i<5;i++) { scanf("%d",a+i); if(a[i]>0) bf=false; } if(bf) break; if(f(23,a,5)==true) printf("Possible\n"); else printf("Impossible\n"); } return 0; }