题解:P1120 小木棍
很简单的搜索题,我的做法暴搜加剪枝,时间复杂度也就 \(O(n!\ m)\) 而已……
- 首先,理清思路,要求原始木棍的最小可能长度。
设答案为 \(ans\),最长的木棍长 \(len\),长度总和为 \(sum\)。那么 \(ans \in [len,sum]\),这是必然的。
那么不妨从最大的木棍长度一直搜索到所有木棍的总和,如果长度可以,那么直接输出答案。
虽然保证了 \(a_i \le 50\),但保险起见,我们用一个桶来记录数量。
- 然后,考虑如何设计 dfs 的状态。
由于我们是从最大的木棍长度一直搜索到所有木棍的总和,所以首先必然要有 当前可以使用的最长木棍的长度 \(len\) 和 需要得到的木棍的长度 \(need\)。
到底几根呢?所以还要有 还需要拼凑得到的木棍数量 \(res\) 以及 当前已经拼凑得到的木棍的长度 \(l\)。
- 最后,考虑如何解决。
- 边界条件是拼完了,即 \(res = 0\)。
- 如果当前拼凑出的木棍的长度等于需要得到的木棍的长度,则开始拼凑下一根。
- 直接从最大往最小暴力,判断是否可行,即小木棍数量是否大于 0,且当前木棍长度 \(i + l <= need\)。
Code
#include <bits/stdc++.h>
#define qwq(i,a,b) for(int i=(a);i<=(b);++i)
#define qaq(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
const int N = 70;
int sum = 0;
int n, cnt;
int a[N];
int mx, mn;
/*
如何设计 dfs?
考虑一下。。。。。。。。。
已知:要拼木棍。
可以这样设计:
还需要拼凑得到的木棍数量、
当前已经拼凑得到的木棍的长度、
需要得到的木棍的长度、
当前可以使用的最长木棍的长度。
那么直接搞。
*/
inline void dfs(int res, int l, int need, int len) {
// cout << res << ' ' << l << ' ' << need << ' ' << len << '\n';
if (res == 0) {
cout << need;
exit(0);
}
// 如果当前拼凑出的木棍的长度等于需要得到的木棍的长度,则开始拼凑下一根
if (l == need) {
dfs(res - 1, 0, need, mx);
}
// 直接从最大往最小暴力
qaq (i, len, mn) {
// 如果可行,即小木棍数量 > 0,且当前木棍长度 i + l <= need
if (a[i] && i + l <= need) {
a[i]--; // 用一根木棍
dfs(res, l + i, need, i);
a[i]++;
if (l == 0 || i + l == need) return ;
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
qwq (i, 1, n) {
int x;
cin >> x;
if (x > 50) continue;
a[x]++;
cnt++;
sum += x;
mx = max(mx, x);
mn = min(mn, x);
}
/*
答案必然 >= 最长的木棍,那么不妨从最大的木棍长度一直搜索到所有木棍的总和,如果长度可以,那么直接输出答案。
*/
qwq (i, mx, sum >> 1) {
if (sum % i != 0) continue; // 优化 1:因为拼成的长度相等,所以显然有一个数 x,可以整除所有的木棍长度,那么不能整除的直接 continue
else {
dfs(sum / i, 0, i, mx);
}
}
cout << sum;
}

浙公网安备 33010602011771号