您的位置:首页 > 其它

POJ1011-Sticks DFS+剪枝

2013-07-21 10:49 246 查看
题目链接:http://poj.org/problem?id=1011

题目大意是有一些等长的木棍,现将他们剪成小木棍,剪短后的小木棍最多有六十四根。题目输入数据给定剪短后的小木棍的长度,求将其恢复成原来的木棍的最短长度。

本题剪枝要求较高:

剪枝(1):由于小木棍是由原来木棍剪短后得到的,那么原来木棍的长度最短的也大于等于最长的小木棍,但不会超过所有小木棍长度之和;

剪枝(2):注意到原木棍长度是等长的,则将所有小木的长度加起来后,若不能按当前要搜索的值平均分配,那么剪掉。

qsort(a,n,sizeof(int),cmp);  //将所有小木棍按从大到小的顺序排序
for (i=a[0];i<=sum;i++)      //我们只需枚举 最长的小木棍长度 到 所有小木棍长度之和。
{
if (sum%i==0&&dfs(0,0,0,i)) //如果所有小木棍长度之和不能按当前要搜索的值平均分配,那么剪掉不搜索。因为原木棍长度等长。
{
break;
}
}


剪枝(3):由于所有棒子已降序排序,在DFS时,若某根棒子不合适,则跳过其后面所有与它等长的棒子;

剪枝(4):最重要的剪枝,开始没加这个剪枝,我TL,加了这个剪枝后,POJ上16ms。对于每次重新构造原始木棍长度时,若从第一根木棍开始搜索,无法组合成功,则不需要继续往后搜索,因为当前木棍若不能和其他木棍组合成原始木棍则就需要被舍弃,但是组成所有的原始木棍不能舍弃任何一根小木棍!

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 70
#define INF 0xfffffff
int a[MAX],flag[MAX];
int n;
int cmp(const void *a,const void *b)
{
return *(int *)b-*(int *)a;
}
int dfs(int tot,int s,int sum,int max)  //四个参数分别为tot-已经使用的小木棍数,s-上次搜索到第几根小木棍
//sum-当前已经组合的小木棍长度,max-原始木棍的长度。
{
if (tot==n) //这是阀值,即所有木棍被用完,搜索结束
{
return 1;
}
int i,sample=-1;;
for (i=s;i<n;i++)
{
if (flag[i]||sample==a[i])   //如果当前木棍被用过了,
//或者与当前木棍等长的小木棍在此次组合成原始木棍中不能用时,当前木棍也不用检索,跳过。剪枝(3);
continue;
flag[i]=1;
if (flag[i]&&sum+a[i]<max)
{
if (dfs(tot+1,i,sum+a[i],max))
{
return 1;
}
else
{
sample=a[i];   //这根木棍在此次组合中不能使用,则记录,下次遇到等长跳过
}
}
else if (sum+a[i]==max)  // 若组合成一根原始木棍
{
if (dfs(tot+1,0,0,max))  //则从从第一根木棍开始搜索,并且将记录的小木棍组合的长度置零重新开始组合另一根原始木棍。
return 1;
else
{
sample=a[i];
}
}
flag[i]=0;
if (sum==0)  //剪枝(4)若上面的木棍组合成功便会return,否则代表无法组合。
break;
}
return 0;
}
int main()
{
while (scanf("%d",&n)!=EOF)
{
if (n==0)
break;
int i,j,sum=0,max=-INF;
for (i=0;i<n;i++)
{
scanf("%d",&a[i]);
flag[i]=0;
sum+=a[i];
}
qsort(a,n,sizeof(int),cmp);
for (i=a[0];i<=sum;i++)
{
if (sum%i==0&&dfs(0,0,0,i))
{
break;
}
}
printf("%d\n",i);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  搜索 DFS POJ1011