poj 1011 Sticks(经典深搜dfs+剪枝)

来源:互联网 发布:单片机脉冲理疗仪原理 编辑:程序博客网 时间:2024/05/15 16:20

1.枚举所有可能的所组成的长度

2.深搜

两个状态(a,b)

a:没有用过的棍的个数

b:当前要组成的棍还需要的长度

初始状态:(n,i)

终止状态:(0,0)

3.剪枝


未剪枝的dfs:

bool dfs(int a,int b){    if(a==0&&b==0)    {        return true;//dfs结束条件    }    if(b==0)    {        b=I;//一根棍子拼完    }    for(int i=0; i<n; i++)    {        if(!flag[i]&&b>=s[i])//如果棍子没有用过,且当前棍s[i]比待填的棍短,        {            flag[i]=1;//则尝试拼接            if(dfs(a-1,b-s[i]))//可以拼接,往后继续搜            return true;            else flag[i]=0;//当前棍拼接失败,标记取消,for尝试下一根棍        }    }    return false;}

搜索题,充满了剪枝的

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;int s[65],I,n,c;bool flag[65];bool dfs(int a,int b){    if(a==0&&b==0)    {        return true;    }    if(b==0)    {        b=I;    }    for(int i=0; i<n; i++)    {        if(!flag[i-1]&&s[i]==s[i-1])            continue;//与上一个未利用的棍有相同长度,同样不会符合,剪枝1        if(!flag[i]&&b>=s[i])        {            flag[i]=1;            if(dfs(a-1,b-s[i]))            {                return true;            }            else            {                flag[i]=0;                if(b==s[i]||b==I)                    return false;//第一个根棍如果不能符合,则第一根放哪都不会符合,剪枝2            }        }    }    return false;}bool cmp(int aa,int bb){    return aa>bb;}int main(){    while(cin>>n&&n)    {        int ttt=0;        int sum,maxn;        sum=0;        maxn=0;        memset(flag,0,sizeof(flag));        for(int i=0; i<n; i++)        {            cin>>s[i];            sum+=s[i];            if(s[i]>maxn)                maxn=s[i];        }        sort(s,s+n,cmp);//从大到小搜索剪枝3        for(int i=maxn; i<=sum/2; i++)//枚举剪枝4        {            I=i;            if(sum%i==0&&dfs(n,i))            {                ttt=1;                cout<<i<<endl;                break;            }        }        if(!ttt)//不要忘了这种情况            cout<<sum<<endl;    }    return 0;}

应该还会有很多剪枝情况,嗯。。

0 0
原创粉丝点击