题目链接:http://poj.org/problem?id=1011
本题是第深搜以及剪枝的考察,题目的大意是给了你有限个棍子以及每个棍子的长度,而且所有的棍子都是由有限个长度相同的棍子截断得到的,让你求被截棍子的最小长度,本题的算法是深搜,当然需要几个剪枝的!
剪枝一:将所有题目给的棍子的长度按照从大到小的顺序排列,然后按照此顺序进行深搜的,因为我们是按照从长度1到所有棍子的总长度进行搜的,这样从大到小可以减去一定步骤的。
剪枝二:如果第i个棍子不能拼成假设的长度,则和第i个棍子相同长度的棍子也是不可能的,所以可以直接跳过去的!
剪枝三:对于第i个棍子,如果找不到任何一个或者多个棍子和它拼成假设的长度,则说明这个假设的长度四不成力的,则直接跳过去的!
#include<iostream>
using namespace std;
int sum,a[100];
bool vis[100];
int cmp(const void *a,const void *b)
{
return *(int *)b-*(int *)a;
}
int dfs(int len,int n,int stick,int ret)//应拼成的长度,帮总共的数量,已拼成的个数的
{
if(stick==n && ret==0)//ret是代表的是以及一个棒已经拼的长度的
return len;//如果所有的棒都已经用完的话
if(ret==0)//这代表一个已经拼完啦!
ret=len;
int i;
for(i=0; i<n; i++)
{
if(vis[i]==true)
continue;
if(a[i]>ret)
continue;//代表的是已经不满足题意了,直接要跳出大循环的
vis[i]=true;
if(dfs(len,n,stick+1,ret-a[i]))
return len;
vis[i]=false;
if(ret==a[i] || len==ret)//最重要的剪枝,如果找不到任意一个枝和当前的枝进行匹配,则说明不可能对了,就直接跳出大循环的!
break;
while(a[i]==a[i+1])//剪枝三,第i根没有拼成的话,第i+1根和第i根长度相同的话也就拼不成了,剪去的
i++;
}
return 0;
}
int main()
{
int i,j,n,k;
while(1)
{
cin>>n;
if(n==0)
break;
sum=0;
for(i=0; i<n; i++)
{
cin>>a[i];
sum+=a[i];
}
qsort(a,n,sizeof(int),cmp);//剪枝一,按照棍子从大到小排列的,然后直接舍弃总棍子太小的
for(i=1; i<=sum; i++)
{
if(sum%i!=0)
continue;//本来就不可以的啊
for(j=0; j<n; j++)
vis[j]=false;//初始化的
k=dfs(i,n,0,i);
if(k!=0)
break;
}
cout<<k<<endl;
}
return 0;
}