题意:
输入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>