POJ 1011Sticks

来源:互联网 发布:小天才早教机软件下载 编辑:程序博客网 时间:2024/06/14 14:34

题意为给你一些木棍,让你将它们拼成数量不限的等长木棍,求这个等长最短是多少。

一道dfs专练剪枝题。对于dfs的状态都很好设计,开始可以设计为dfs(int nowpos,int nowlen,int dep,int lef),表示现在考虑到第几根了,现在拼成的长度,现在尝试的限制长度,剩下的根数。

首先我们对于枚举的方法入手,第一眼我们会发现这个dep也就是限长一定是总长度的因子,这样就迅速减少了一些无用状态。

紧接着我们可以考虑枚举的顺序,如果从小到大枚举的话,dfs到结果那么一定是最优的,所以每当搜索到结果便可以直接输出答案,有点类似于A*搜索的思想。

可是这时发现还是不能过,我们只能向搜索里面下手了。

我们先再读一遍题,长度不超过五十,但是却有很多木棒,那么一定会有大量的重复。我们可以考虑将木棒大小排序,如果选这一个不可以的话,那么后面与它等长的必定都不可以,如果选这个可以,那么选后面和它一样的也可以。又实现了一大优化,

最后一步,也是最细节的一步,如果现在我们的nowlen长度为0,在第一部循环中dfs没有找到结果,这个状态后面的所有循环一定是找不到结果,因为长度为0的话,任意一个木棍都是可以加进来的,如果没有找到结果,意味着这个状态肯定是无结果的。

以上便是可以达到AC的剪枝了。

下附AC代码。

#include<iostream>#include<string.h>#include<algorithm>#define maxn 70using namespace std;int n;int stick[maxn];int vis[maxn];int cmp(int i,int j){return i>j;}int dfs(int nowpos,int nowlen,int dep,int lef){if(lef==0)return true;int pre=-1;for(int i=nowpos;i<=n;i++){if(vis[i] || stick[i]==pre) continue;vis[i]=1;if(nowlen+stick[i]<dep){if(dfs(nowpos+1,nowlen+stick[i],dep,lef-1))return true;elsepre=stick[i];}if(nowlen+stick[i]==dep){if(dfs(1,0,dep,lef-1))return true;else pre=stick[i];}vis[i]=0;if(nowlen==0)break;}return false;}int main(){while(cin>>n && n){int sum=0;memset(vis,0,sizeof(vis));for(int i=1;i<=n;i++){cin>>stick[i];sum+=stick[i];}sort(stick+1,stick+1+n,cmp);int flag=true;for(int i=stick[1];i<=sum-stick[1];i++){if(sum%i==0){if(dfs(1,0,i,n)){cout<<i<<endl;flag=false;break;}}}if(flag)cout<<sum<<endl;}}

原创粉丝点击