题意:一开始有n根同样的小木棍,后来将其切成长度不超过50的小木棍,问原来小木棍最短长度是多少,例如砍完后有四根,长度分别为1,2,3,4,原来长度可能为5,或10。5是最小可能长度。
分析:可以用深搜,因为它的组成长度可能性只是所有木棍长度总和的因数,所以可以直接dfs。
注意剪枝,四个剪枝:
1、当前枚举的长木棍长度不是小木棍长的和的因数时跳过。
2、与当前小木棍长度相同的小木棍没有使用,当前小木棍也不会使用。
3、当前是拼新的长木棍的第一个小木棍,而最后无法拼成的,直接回溯。
4、一根木棍补足长木棍剩余所需长度,而最后无法拼成的,直接回溯。
# include<iostream>
# include<cstdio>
# include<cmath>
# include<map>
# include<queue>
# include<string>
# include<string.h>
#include<set>
#include<list>
# include<algorithm>
using namespace std;
const int maxn = 65536;
int a[maxn];
int len;
int maxd;
int vis[maxn];
bool cmp(int u, int v) { return u > v; }
bool dfs(int sum,int cur,int res,int k) {
if (res==maxd) {
return true;
}
for (int i =cur ; i < len; i++) {
if (vis[i] || (i&&a[i] == a[i - 1] && !vis[i - 1]))continue;//相同长度的之前没使用,所以这里一样不使用
if (a[i] + sum == k) {//成功拼成一个小木块
vis[i] = 1;
if (dfs(0, 0, res + 1,k))return true;
vis[i] = 0;
return false;
}
if (a[i] + sum < k) {//没拼好
vis[i] = 1;
if (dfs(a[i] + sum, i + 1, res,k))return true;
vis[i] = 0;
if (!sum)return false;//最后仍不能拼成
}
}
return false;
}
int main() {
while (cin >> len && len) {
int sum=0;
for (int i = 0; i < len; i++) {
cin >> a[i];
sum += a[i];
}
int ok = 0;
sort(a, a + len,cmp);
for (int i = a[0]; i <= sum/2; i++) {//从最大的开始拼
if (sum % i == 0) {
memset(vis, 0, sizeof(vis));
maxd = sum / i;
if (dfs(0, 0,0,i)) { cout << i << endl; ok = 1; break; }
}
}
if (!ok)cout << sum << endl;
}
return 0;
}