题意:
输入n个正整数和一个目标值,可以在这n个数中间填充+ - × /号进行运算,运算从左到右进行,不考虑运算符的优先性。 并且给定下面的规则:
1.填充符号时n个数的顺序不能改变。
2.填充除号的时候必须保证结果为整数。
3.每一步的结果必须在-32000~32000之间。
问是否可以求得目标值。
思路:
很显然可以用dfs+回溯来实现符号的填充,但是直接dfs是绝对会超时的(我就WA了一发);那么我们就要考虑剪枝了,这个题目可以利用状态来进行剪枝:我们记录下每一步得到的结果,如果回溯到这一步并且结果和原先的结果一致的话就可以直接返回。利用这个剪枝就可以AC啦。
还有就是每一步计算的结果都有可能为负数,为了利用数组进行判重,我们需要把结果加上50000后作为数组下标。
代码如下:
<span style="font-size:18px;">#include<iostream> #include<cstring> #include<cstdio> using namespace std; int a[110],n,flag,goal,vis[110][90000]; char ans[110]; inline int check(int a,int cur) { if(a>=-32000&&a<=32000&&!vis[cur][a+50000]) { vis[cur][a+50000]=1; return 1; } return 0; } void dfs(int cur,int sum) { if(cur==n-1) { if(sum==goal) { ans[cur]='='; for(int i=0;i<n;i++) printf("%d%c",a[i],ans[i]); printf("%d\n",goal); flag=1; } return ; } if(flag) return ; if(check(sum+a[cur+1],cur)) { ans[cur]='+'; dfs(cur+1,sum+a[cur+1]); } if(flag) return ; if(check(sum-a[cur+1],cur)) { ans[cur]='-'; dfs(cur+1,sum-a[cur+1]); } if(flag) return ; if(check(sum*a[cur+1],cur)) { ans[cur]='*'; dfs(cur+1,sum*a[cur+1]); } if(flag) return ; if(sum%a[cur+1]==0&&check(sum/a[cur+1],cur)) { ans[cur]='/'; dfs(cur+1,sum/a[cur+1]); } if(flag) return ; } int main() { int i,j,t; scanf("%d",&t); while(t--) { memset(vis,0,sizeof(vis)); scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&a[i]); scanf("%d",&goal); flag=0; dfs(0,a[0]); if(!flag) printf("NO EXPRESSION\n"); } return 0; }</span>
时间: 2024-10-19 04:21:50