版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84061409
思路分析:
使用DFS, 考虑如下剪枝策略:
(1)按照木棒长度非递减的顺序拼接每根原始木棒
(2)如果当前正在拼接某根原始木棒的第一个时即失败, 那么直接回溯(不同的空木棒是等价的)
(3)如果用长度为a的木棒使得当前正在拼接的木棒达到设定的原始木棒长度时宣告失败, 那么尝试使用更多根长度小于a的木棒拼接当前木棒为原始木棒长度也必定失败.
(4)记录最后一个使用其失败的木棒长度, 并在接下在的尝试中不再使用
根据上述剪枝策略给出如下AC代码:
//POJ1011_Sticks
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX = 100, NIL = 0x3f3f3f3f;
int sti[MAX], N, used[MAX], len, size;//共N根木棍, used[i]非零表示木棍被占用, 为0不占用
//当前已拼接好now - 1个长度为len的木棍, 正在拼第now个, 且第now个已经拼接长度为nowlen, 共需拼接size个
//每个木棍非递减的选择木棒, 最后选择的木棍长度不大于lastlen
bool dfs(int now, int nowlen, int lastlen){
if(now > size) return true;
for(int i = 1, last = NIL, k, ok; i <= N; ++i)
if(!used[i] && sti[i] != last && sti[i] <= lastlen && (k = nowlen + sti[i]) <= len){
used[i] = 1, ok = k == len? dfs(now + 1, 0, NIL): dfs(now, k, sti[i]), used[i] = 0;
if(ok) return true;
if(!nowlen || k == len) return false;
}
return false;
}
int main(){
while(scanf("%d", &N), N){
memset(used, 0, sizeof(used));
int sum = 0; for(int i = 1; i <= N; ++i) scanf("%d", &sti[i]), sum += sti[i];
sort(sti + 1, sti + N + 1), reverse(sti + 1, sti + N + 1), len = 1;
for(int find = 0; !find && len <= sum; ++len)
if(!(sum % len))
size = sum / len, find = dfs(1, 0, NIL);
cout << len - 1 << endl;
}
return 0;
}