这题难度很唬人呀!!!
题目描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 50 50 50。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入格式
第一行是一个整数
n
n
n,表示小木棍的个数。
第二行有
n
n
n 个整数,表示各个木棍的长度
a
i
a_i
ai。
输出格式
输出一行一个整数表示答案。
样例 #1
样例输入 #1
9
5 2 1 5 2 1 5 2 1
样例输出 #1
6
提示
对于全部测试点, 1 ≤ n ≤ 65 1 \leq n \leq 65 1≤n≤65, 1 ≤ a i ≤ 50 1 \leq a_i \leq 50 1≤ai≤50。
解析
先算出小木棍总长度。再枚举木棒长度。最后再搜索判断是否能成功。
本题需要极多(四五个)剪枝。具体剪枝见代码内部。
AC代码
/*
优化1:从所有小木棍最长的长度枚举
优化2:答案必须是所有小木棍总长度的约数
优化3:拼每个木棒,保证后面的小木棍不大于前面的小木棍
优化4:等效冗余,某一个长度小木棍拼接失败
优化5:如果摸一个木棒,第一根拼接失败了返回上一层
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n, x, cnt, l, sum, len, tot;
int a[70];
int vis[70];
bool cmp(int x, int y) {
return x > y;
}
bool dfs(int step, int val, int last) {
if (step == tot + 1) {
return 1;
}
if (val == len) {
return dfs(step + 1, 0, step);
}
int fail = 0;
for (int i = last + 1; i <= cnt; i++) {
if (vis[i] == 1 || fail == a[i] || val + a[i] > len) {
continue;
}
vis[i] = 1;
if (dfs(step, val + a[i], i) == 1) {
return 1;
}
fail = a[i];
vis[i] = 0;
if (val == 0 || val + a[i] == len) {
return 0;
}
}
return ; //防直接复制代码
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> x;
if (x <= 50) {
a[++cnt] = x;
l = max(l, x);
sum += x;
}
}
sort(a + 1, a + cnt + 1, cmp);
for (len = l; ; len++) {
if (sum % len != 0) {
continue;
}
tot = sum / len;
if (dfs(1, 0, 0) == 1) {
cout << len << endl;
break;
}
}
return 0;
}