题目大意:
(来源:洛谷)
解题思路:
- 暴力枚举总和的约束,进行搜索
- 将小木棍从大到小排序,因为这样枚举,会使后面有更灵活的组合
- 引用**大佬博客**的两句话:
当前长棍剩余的未拼长度等于当前木棍的长度时,这根木棍在最优情况下显然是拼到这(如果用更多短木根拼完剩下的这段,把这根木棍留到后面显然不如把更多总长相等的短木棍扔到后面)。如果在最优情况下继续拼下去失败了,那肯定是之前的木棍用错了,回溯改即可。
当前长棍剩余的未拼长度等于原始长度时,说明这根原来的长棍还一点没拼,现在正在放入一根木棍。很明显,这根木棍还没有跟其它棍子拼接,如果现在拼下去能成功话,它肯定是能用上的,即自组或与其它还没用的木棍拼接。但继续拼下去却失败,说明现在这根木棍不能用上,无法完成拼接,所以回溯改之前的木棍。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 70;
const int maxv = 3260;
int it_num = 0;
int S, n, l[maxn];
bool vis[maxn], s[maxn][maxv];
bool cmp(int lhs, int rhs) {return lhs > rhs;}
bool dfs(int sum, int val, int num, int pos) {
it_num++;
if (val > sum || pos > n) return false;
if (num == S / sum + 1) {
return true;
}
if (sum == val) return dfs(sum, 0, num + 1, 1);
for (int pf = 0; pos <= n; pos++) {
if (vis[pos] || pf == l[pos] || (sum - val) < l[pos]) continue;
vis[pos] = true;
if (!dfs(sum, val + l[pos], num, pos)) {
vis[pos] = false, pf = l[pos];
if ((sum - val) == l[pos] || val == 0) return false;
}
else
return true;
}
return false;
}
int main() {
cin >> n;
int u, cnt = 0, mlen = 0;
for (int i = 1; i <= n; i++) {
cin >> u;
if (u <= 50) l[++cnt] = u, S += u, mlen = max(mlen, u);
}
n = cnt;
sort(l + 1, l + cnt + 1, cmp);
for (int i = mlen; i <= S; i++) {
if (S % i) continue;
memset(s, 0, sizeof(s));
if (dfs(i, 0, 1, 1)) {
cout << i << endl;
break;
}
}
return 0;
}