题目描述
原题来自:CERC 1995
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 50 。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入格式
第一行为一个单独的整数 N 表示砍过以后的小木棍的总数。 第二行为 N 个用空格隔开的正整数,表示 N 根小木棍的长度。
输出格式
输出仅一行,表示要求的原始木棍的最小可能长度。
样例
输入数据 1
9
5 2 1 5 2 1 5 2 1
Copy
输出数据 1
6
Copy
数据范围与提示
1≤N≤60
#include<bits/stdc++.h>
using namespace std;
int n;
int a[70],vis[70];
int sum,res, ans;
bool cmp(int x,int y)
{
return x > y;
}
int dfs(int len,int sta,int now)//(当前剩余的长度,搜索到第几根木棍,已经用了几次)
{
int i,j;
if(now == res)return 1;
if(len == 0)//用完了进行下一次
if(dfs(ans,1,now + 1))//每次都要从头开始搜索
return 1;
for(i = sta;i <= n;i ++)//挑选下一根木棍
{
if(!vis[i] && a[i] <= len)//该木棍之前还没有选过且长度合理
{
vis[i] = 1;//选上
if(dfs(len - a[i],i + 1,now))//因为是从大到小挑选的,i + 1可以保证不会从小的挑到大的
return 1;
vis[i] = 0;//回溯
if(ans == len)break;
while(a[i] == a[i + 1])i ++;
/*
如果ans==len说明有比原长度更大的木棍出现,那就不可能塞得下了,所以可以剪枝
去重剪枝 相同长度的不符合条件的则不需再搜索
*/
}
}
return 0;
}
int main()
{
cin >> n;
int i,j;
for(i = 1;i <= n;i ++)
{
cin >> a[i];
sum += a[i];
}
sort(a + 1,a + 1 + n,cmp);//先配大的,再配小的,因为小的作用更大
for(j = a[1];j <= sum;j ++)
{
if(sum % j)continue;//如果除不尽就跳过
res = sum / j;//分成的根数
ans = j;//更新答案
if(dfs(ans,1,0))
{
cout << ans << endl;
}
}
}