http://poj.org/problem?id=1011
这题主要在剪枝上下功夫,十分十分经典的一道搜索,方法是从n到1倒着来搜,当在某一处时,所有的stick能够完美组成sum/i这一长度,就break。
经典题,非常好,这题对递归、搜索会有更深刻理解。
#include <vector>
#include <list>
#include <map>
#include <set>
#include <string.h>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
#define LL long long
#define pi acos(-1)
#define N 5000
#define INF 999999999
#define eps 1e-8
//****************************************
//poj 1011 dfs
//Copyright@leolin All rights reserved.
//****************************************
int a[100];
bool vis[100];
int n,ans;
bool dfs(int used,int pos,int len)
{
int i,j;
if(used==n)return true;
for(i=pos;i<n;i++)
{
if(vis[i]) continue;
if(len+a[i]<ans)
{
vis[i]=true;
if(dfs(used+1,i+1,len+a[i])) return true;
vis[i]=false;//如果dfs(used+1,i+1,len+a[i])返回false,则第i根不可用,标记为false
while(a[i]==a[i+1] && i+1<n)//如果前面一个相等长度的棍子没有用上,那么这个也用不上,重要剪枝
{
i++;
}if(len==0) return false;//如果当前长度为0,证明没有合适的,return false
}
else
if(len+a[i]==ans)
{
vis[i]=true;
if(dfs(used+1,0,0)) return true;
vis[i]=false;
return false;
}
}
return false;
}
int main()
{
while(scanf("%d",&n)&&n)
{
int i,j,k;
int sum=0,maxm=0;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
maxm=max(maxm,a[i]);
}
sort(a,a+n,greater<int>() );//从大到小排序可减少递归次数
for(i=n;i>0;i--)
{
if(sum%i==0 && (sum/i)>=maxm)
{
ans=sum/i;
memset(vis,false,sizeof(vis));
if(dfs(0,0,0))
{
printf("%d\n",ans);
break;
}
}
}
}
return 0;
}