您的位置:首页 > 其它

POJ 1011 Sticks

2017-08-17 09:07 204 查看
题意为给你一些木棍,让你将它们拼成数量不限的等长木棍,求这个等长最短是多少。

一道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 70
using 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;
else
pre=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++)
4000
{
if(sum%i==0)
{
if(dfs(1,0,i,n))
{
cout<<i<<endl;
flag=false;
break;
}
}
}
if(flag)
cout<<sum<<endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: