题意:n根长度不同的小棍,拼成若干根长棍,要这些长棍的长度相等,并且小棍刚好都用完,问能拼成的长棍的最短长度是多少。
思路:首先把小棍按长度,从大到小排序(为了进行贪心选择,要先选长的,留着短的灵活组合),计算出这些小棍的总长度,把当前要进行深搜的nowl从a[1]开始搜索,如果小棍的总长度sum能整除nowl,则对nowl进行深搜;如果深搜成功则输出nowl;否则nowl++直到nowl等于sum.最坏的情况下nowl == sum 时,搜索才成功。就是所有的小木棍拼成一根长棍,所以深搜可以成功。搜索细节见代码注释!
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 88;
int a[MAXN], used[MAXN], n, m, nowl;
int cmp(int aa, int bb) {
return aa >= bb;
}
//注意只有一根组合棍完成才能过渡到下一根。
bool dfs(int k, int len, int l) { //k表示当前组合好的棍子数,len表示当前这根组合棍的长度,l表示搜索到第几根。
int i;
int flag = len == 0 ? 1:0;
if (k == m) return true; //全部组合成功,
for(i = l; i <= n; i++) {
if (used[i]) continue; //如果第i根棍子已经被组合,则跳过;
if (len+a[i] == nowl) {//如果当前这根组合棍符合要求,标记第i根棍子;
used[i] = 1;
if (dfs(k+1, 0, 1))//如果后面的棍子能组合成功,那么说明nowl可行。
return true;
used[i] = 0;
return false;//如果后面的棍子不能组合成功,就要返回false。
}
else if (len + a[i] < nowl) {//如果当前组合棍组合第i根棍子还是没有nowl长;
used[i] = 1; //标记这根棍子
if (dfs(k, len+a[i], i+1))//一样的,有人会问为什么是i+1,额,我也不会解释,自己体会下吧^.^!
return true;
used[i] = 0;
if (flag) return false;//如果这根组合棍还只有i这根棍子,它后面也没组合成功就可以返回false了。
while (a[i+1] == a[i] && i < n) i++;//只有满足前面所有的优化时,此优化才可以做,自己体会下,啊哈哈哈、、、
}
}
return 0;
}
int main() {
int sum;
while (scanf("%d", &n) && n) {
sum = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum += a[i];
}
sort(a+1, a+n+1, cmp);
for(nowl = a[1]; nowl <= sum; nowl++)
if (sum%nowl == 0) {
m = sum/nowl;
memset(used, 0, sizeof(used));//稍微注意下,别急!
if (dfs(0, 0, 1)) {
printf("%d\n", nowl);
break;
}
}
}
return 0;
}