UVA_307

相当于重温了一下POJ 1011这个题目,剪枝在这个题目中显得尤为重要。

对于这道题而言,剪枝的策略一般有下面6个:

①先将木棒长度从大到小进行排序,这样便于后面的选择和操作,是后面一些剪枝算法的前提。

②在枚举原木棒长度时,枚举的范围为maxsum/2之间,如果这个区间内没有找到合适的长度,那么最后原木棒的长度只能是sum

③枚举的原木棒的长度只能是sum的约数。

④在深搜过程中,如果当前木棒和前一个木棒的长度是一样的,但是前一个木棒没有被选上,那么这个木棒也一定不会被选上。

⑤在深搜过程中,如果当前是在拼一根新木棒的第一截,但如果把可用的最长的一根木棒用上后不能拼成功的话,那么就不用再试后面的木棒了,肯定是前面拼的过程出了问题。

⑥在深搜过程中,如果当前可用的木棒恰好能补上一根原木棒的最后一截,但用它补上之后却不能用剩下的木棒完成后续的任务,那么也不用再试后面的木棒了,肯定是前面拼的过程出了问题。

#include<stdio.h>
#include
<string.h>
#include
<stdlib.h>
int sum,N,n,L,a[100],vis[100];
int cmp(const void *_p,const void *_q)
{
int *p=(int *)_p;
int *q=(int *)_q;
return *q-*p;
}
int dfs(cur,complete,len)
{
int i;
if(len==L)
{
complete
++;
if(complete==N)
return 1;
else
{
for(cur=0;vis[cur];cur++);
vis[cur]
=1;
if(dfs(cur+1,complete,a[cur]))
return 1;
vis[cur]
=0;
}
}
else
{
for(i=cur;i<n;i++)
if(!vis[i]&&a[i]<=L-len)
{
if(i!=0&&a[i]==a[i-1]&&!vis[i-1])
continue;
vis[i]
=1;
if(dfs(i+1,complete,len+a[i]))
return 1;
vis[i]
=0;
if(a[i]==L-len)
return 0;
}
}
return 0;
}
int main()
{
int i,j,k,max;
while(1)
{
scanf(
"%d",&n);
if(n==0)
break;
sum
=max=0;
for(i=0;i<n;i++)
{
scanf(
"%d",&a[i]);
if(a[i]>max)
max
=a[i];
sum
+=a[i];
}
qsort(a,n,
sizeof(a[0]),cmp);
memset(vis,
0,sizeof(vis));
for(L=max;L<=sum/2;L++)
{
if(sum%L!=0)
continue;
N
=sum/L;
if(dfs(0,0,0))
break;
}
if(L>sum/2)
printf(
"%d\n",sum);
else
printf(
"%d\n",L);
}
return 0;
}

  

posted on 2011-09-08 14:30  Staginner  阅读(856)  评论(0编辑  收藏  举报