【分析】
经典小木棍题。
用 dfs(i,j,k) 。i代表拼当前木棍还剩的长度,j表示只能从第j个木棍往后使用木棍,k代表已经拼好了几组木棍。
解释见代码
【代码】
//P1120 小木棍 [数据加强版]
#include<algorithm>
#include<cstdio>
#define fo(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
int n,sum,len,tot,ans;
int a[101];
bool vis[101];
bool cmp(int x,int y) {return x>y;}
bool dfs(int now,int next,int d)
{
if(d==tot)
{ans=len;return 1;}
if(now==0) {if(dfs(len,1,d+1)) return 1;}
fo(i,next,n)
if(!vis[i] && a[i]<=now)
{
vis[i]=1;
if(dfs(now-a[i],i+1,d)) return 1;
vis[i]=0;
if(now==a[i] || now==len) break; //如果使用当前木棍之后依然无法拼好,且该木棍正好能补全要当前要拼成的木棍,那么跳出。如果now=len,也就是说now是新一组木棍的开始,但用了剩下木棍中最大的木棍都拼不了,那么跳出。
while(a[i+1]==a[i]) i++; //相同长度木棍试几次都是失败。
}
return 0;
}
int main()
{
scanf("%d",&n);
fo(i,1,n)
{
scanf("%d",&a[i]);
if(a[i]>50) n--,i--;
else sum+=a[i];
}
sort(a+1,a+n+1,cmp); //排序后便于剪枝
for(len=a[1];len<=sum;len++) //枚举长度
if(sum%len==0)
{
tot=sum/len;
if(dfs(len,1,0)) break;
}
printf("%d\n",ans);
return 0;
}
//9
//5 2 1 5 2 1 5 2 1