http://poj.org/problem?id=1011
题目大意:George有一捆相同长度的木棍,但是他把这些木棍砍段了,现在想知道这些木棍原来长度是多少(即还原木棍),求可能的最小的原木棍长度。
代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
int n,stick[64],use[64],len;
bool cmp(int a,int b)
{
return a>b;
}
bool dfs(int i,int l,int t)
{
if(l==0)
{
t-=len;//这说明匹配到1根长度为len的木棍
if(t==0) return true;
for(i=0;use[i];i++);//再去匹配下一根木棍
use[i]=1;
if(dfs(i+1,len-stick[i],t)) return true;//如果匹配不到下一根就直接退出搜索,去匹配下一个长度
use[i]=0;
t+=len;
}
else
{
for(int j=i;j<n;j++)
{
if(j>0&&stick[j-1]==stick[j]&&!use[j-1])//<span style="color:#ff0000;">(强大剪枝)</span>如果前后两根木棍相等,若前面那根没被标记就说明前面那根搜索失败,那这根搜索也肯定失败
continue;
if(!use[j]&&l>=stick[j])
{
l-=stick[j];
use[j]=1;
if(dfs(j,l,t)) return true;
l+=stick[j];
use[j]=0;
}
}
}
return false;
}
int main()
{
int i,sum;
bool flag;
while(cin>>n&&n)
{
sum=0;
flag=false;
for(i=0;i<n;i++)
{
cin>>stick[i];
sum+=stick[i];
use[i]=0;
}
sort(stick,stick+n,cmp);<span style="color:#ff0000;">(强大剪枝)</span>
for(len=stick[0];len<=sum/2;len++)//如果棍子分不成两根一样长的就说明只有一根
{
if(sum%len==0)//<span style="color:#ff0000;">(强大剪枝)</span>棍子的长度肯定是总长度因数
{
if(dfs(0,len,sum))//从头开始匹配长度为len的棍子
{
flag=true;
cout<<len<<endl;
break;
}
}
}
if(!flag)
cout<<sum<<endl;
}
return 0;
}