《算法竞赛进阶指南》0x22dfs 经典搜索剪枝 第三遍做了
作者:互联网
题目链接;http://poj.org/problem?id=1011
又是拼木棍呀,不过这次我是对他的剪枝原理完全弄清楚了,最后两条剪枝还真的是很难想到的。这次的剪枝中加入了一条:我们在某一跟木棍中拼接时,选择的木棍长度是递减的,这样就保证了搜索树中不会有重叠的部分,不过其实在木棍中,小木棒是无序的,可以用这个策略来证明剪枝的正确性,也就是说,拼第一根失败和拼最后一根失败之后,这个分支就不可能搜索到最终状态了。
代码:
#include<iostream> #include<cstdio> #include<string.h> #include<algorithm> using namespace std; #define maxn 100 int a[maxn],len,cnt,n; int vis[maxn]; int sum; int fail;//上一次拼接失败的木棍的长度 //last用来保证我们选择木棒的时候是按照递减的顺序选取的,防止搜索同样的状态空间 bool dfs(int stick,int cab,int last){//状态分别是当前在拼的是第几根木棍,当前木棍长度,开始选择的编号 if(stick==cnt+1)return true; if(cab==len)return dfs(stick+1,0,1);//新的木棍从第一根开始重新选择人拼接方案 fail=0; for(int i = last; i<=n;i++){ if(!vis[i] && cab+a[i]<=len && a[i]!=fail){//没用过并且能拼并且不是失败决策 vis[i]=1; if(dfs(stick,cab+a[i],i+1))return true; fail=a[i];//记录本次拼接失败的 木棒长度 vis[i]=0; if(cab==0 || cab+a[i]==len)return false; } } return false; } bool cmp(int &a,int &b){return a>b;} int main(){ while(cin>>n && n){ sum=0; int minlen=-0x7f7f7f7f; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum+=a[i]; minlen=max(minlen,a[i]); } sort(a+1,a+n+1,cmp);//降序,优先考虑决策少的方案 for(int i=minlen;i<=sum;i++){ if(sum%i)continue; len=i; cnt=sum/len; memset(vis,0,sizeof(vis)); if(dfs(1,0,1))break; } cout<<len<<endl; } }
标签:剪枝,last,进阶,0x22dfs,int,stick,木棍,include 来源: https://www.cnblogs.com/randy-lo/p/13162204.html