您的位置:首页 > 其它

poj 1011 sticks 搜索加剪枝

2010-10-25 16:10 316 查看
题目描述:

木棒

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 75149 Accepted: 16564
Description
乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
Input
输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。
Output
为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample Output
6
5

此题我不会做,所以把别人的解体思路给记录下来,方便自己以后用的时候看.

用dfs,然后在一下这几个方面剪枝:

1. 搜索顺序。首先依据小棒长度进行由大到小的排序,在每一层搜索时首先将长度大的小棒填入当前原棒

中。

因为当相对长的小棒占据了原棒的大部分空间后能大大减小可行的搜索状态。

2. 利用排序剪枝。在组合同一支原棒的时候,由于检验小棒是否可用的顺序也是由大到小的,因此在检验

到一支小棒可用时,如果当前棒还合填满,可能填入当前棒的 小棒的长度也不会比现在填入的这支小棒长。

因此,增加一个递归参数NEXT表示可能用于组合当前棒的第一支小棒的数组下标。参数传递时,若当前正好

拼成一 支原棒,NEXT还原回1,否则将NEXT+1传递给下一层递归。

3. 不进行重复搜索。

别人 0ms ac的代码:
#include<iostream>
#include<algorithm>
using namespace std;
int sticks[64],n,len,num;
bool used[64];
bool compare(int a,int b)
{
return a>b;
}
bool dfs(int cur,int left,int level)
{
if(left==0)
{
if(level==num-2)
return true;
for(cur=0;used[cur];cur++);
used[cur]=true;
if(dfs(cur+1,len-sticks[cur],level+1))
return true;
used[cur]=false;
return false;
}else
{
if(cur>=n-1)return false;
for(int i=cur;i<n;i++)
{
if(used[i])continue;
if((sticks[i]==sticks[i-1])&&!used[i-1])
continue;
if(sticks[i]>left)continue;
used[i]=true;
if(dfs(i,left-sticks[i],level))
return true;
used[i]=false;
}
return false;
}
}

int main()
{
freopen("in.txt","r",stdin);
while(scanf("%d",&n),n)
{
int sum=0;
for(int i=0;i<n;i++)
{
scanf("%d",&sticks[i]);
sum+=sticks[i];
}
sort(sticks,sticks+n,compare);
bool end=false;
for(len=sticks[0];len<=sum/2;len++)
{
if(sum%len==0)
{
used[0]=true;
num=sum/len;
if(dfs(0,len-sticks[0],0))
{
end=true;
printf("%d/n",len);
break;
}
used[0]=false;
}
}
if(!end)printf("%d/n",sum);
memset(used,0,sizeof(used));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: