参考博文:https://www.cnblogs.com/zqy123/p/4921564.html
问题分析:
原棍子长度范围在锯断后最长的棍子长度到所有棍子的总长度之内,所以从小到大循环遍历可能的原棍子长度,符合条件的长度即结果。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int Max = 65;
int sticks[Max]; //存储每根棍子的长度
int note[Max]; //记录当前下标的棍子是否用过
int sticks_len; //要合成的棍子的长度
int sticks_num; // 长度为sticks_len下一共有多少根棍子
int sticks_sum; //所有棍子的总长度
int num;
int dfs(int n, int k, int cnt) { //n为正在合并的棍子的长度,k为当前要处理的木棍的下标,cnt为已经合成好的棍子的数量
if (cnt == num) return 1;
if (n == sticks_len) //已经合并好一根棍子,继续合下一根
return dfs(0,0,cnt+1);
int i,pre = 0; //i是木棍的下标,pre保存重复木棍
for (i = k; i < sticks_num; i++) {
if (note[i] == 0 && n+sticks[i] <= sticks_len && sticks[i] != pre) { //如果当前选择棍子的长度是pre,则下一根选择的棍子的长度要小于pre,降低运行时间
pre = sticks[i];
note[i] = 1;
if (dfs(n+sticks[i], i+1, cnt))
break;
note[i] = 0;
if (k == 0)//如果第一根棍子(最长的那根)不能参与合成,那么其余的棍子也无法合成
return 0;
}
}
if (i == sticks_num)
return 0;
else
return 1;
}
int main() {
while (cin >> sticks_num, sticks_num != 0) {
sticks_sum = 0;
for (int i = 0; i < sticks_num; i++) {
cin >> sticks[i];
sticks_sum += sticks[i];
}
sort(sticks, sticks+sticks_num, greater<int>());
for (sticks_len = sticks[0]; sticks_len <= sticks_sum/2; sticks_len++) { //循环遍历,原棍子长度等于总长度或小于等于总长度的两倍
if (sticks_sum%sticks_len == 0) { //总长度肯定是原棍子长度的倍数
num = sticks_sum/sticks_len;
memset(note, 0, sizeof(int)*sticks_num); //初始化记录数组,所有棍子都没用过
if (dfs(0,0,0)) break;
}
}
if (sticks_len > sticks_sum/2)
cout << sticks_sum << endl;
else
cout << sticks_len << endl;
}
return 0;
}