吴队长征婚这件事因为请客而没有传出去(虽然他忘了请一个队吃饭),于是吴队长高兴地玩起了木棒。吴队长拿了一些长度相同的木(guang)棒(gun),随机的把它们截成了
N
N段,每一段最长50。现在他想把这些木棒还原成原来的状态,但是他忘记了原来的木棒有多少根,也忘记了每一根有多长
。请帮助他设计一个程序,帮他计算之前木棒可能的最小长度。输入数据保证每一段木棒长度都大于0。
输入有多组数据,每组数据分为两行。
第一行一个整数
N
N,表示截断之后木棒的个数。
1≤N≤64
1≤N≤64
第二行
N
N个整数,表示截断之后的每一段小木棒的长度。 当N=0时,表示输入结束。
每组数据输出一个整数占一行,表示原木棒可能的最小长度。
三种剪枝,首先,原长度肯定>=这些木棒的最大长度,而且能被所有木棒的总长度整除
其次,搜索的时候,肯定不能搜合成之后比当前假设长度长的。
还有,如果某个木棒在这个状态搜索失败,那所有与这个木棒相同长度的木棒就不用在这次搜索中搜索了
还有,如果当前搜出了一个符合长度的,那么它肯定是一个合法的情况,就不需要拆它了。
还有,如果当前已有长度为0,但是当前搜的这根木棒无法合成满足要求的木棒,这个长度肯定是不符合要求的,直接return false就可以。当然,与此对应的就是,如果当前这个木棒在合成后正好符合长度要求,但是之后的搜索确实失败的,说明后面也无法合成满足要求的木棒,也直接return false就可以
刚开始自己想的时候,想了半天,也没有写出好点的dfs,最后还是去搜了别人的代码,然后理解了理解,自己仿照着写的,所以基本差不多,思路还是枚举所有的组合情况,但是剪枝确实可以剪好多
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 66
int n, sum, nt, lent;
int a[maxn];
bool mark[maxn];
bool cmp(int a, int b)
{
return a > b;
}
bool dfs(int cnt,int now,int pos)
{
if (now == lent)
{
now = 0;
pos = 0;
++cnt;
}
if (cnt == nt)
return true;
for (int i = pos; i < n; ++i)
{
if (mark[i] == false && a[i] + now <= lent)
{
mark[i] = true;
if (dfs(cnt, now + a[i], i + 1))
return true;
mark[i] = false;
if (now == 0 || now + a[i] == lent)
return false;
for (int j = i + 1; j < n; ++j)
{
if (a[i] == a[j])
++i;
}
}
}
return false;
}
int main()
{
//freopen("input.txt", "r", stdin);
while (scanf("%d", &n))
{
if (n == 0)
break;
sum = 0;
for (int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
sum += a[i];
}
sort(a, a + n, cmp);
bool f = 1;
for (int i = a[0]; i <= sum / 2; ++i)
{
if (sum%i != 0)
continue;
memset(mark, false, sizeof(bool)*maxn);
lent = i, nt = sum / i;
if (dfs(0, 0, 0))
{
f = 0;
printf("%d\n", i);
break;
}
}
if (f)
printf("%d\n", sum);
}
//system("pause");
//while (1);
return 0;
}