uva--10400+dfs+回溯

来源:互联网 发布:类似wiboxls的软件 编辑:程序博客网 时间:2024/06/05 18:55

题意:

    输入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>



1 0
原创粉丝点击