AcWing 167. 木棒
宋标 Lv5

题目

乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过 个长度单位。

然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。

请你设计一个程序,帮助乔治计算木棒的可能最小长度。

每一节木棍的长度都用大于零的整数表示。

输入格式

输入包含多组数据,每组数据包括两行。

第一行是一个不超过 的整数,表示砍断之后共有多少节木棍。

第二行是截断以后,所得到的各节木棍的长度。

在最后一组数据之后,是一个零。

输出格式

为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。

数据范围

数据保证每一节木棍的长度均不大于

输入样例:

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

输出样例:

6
5

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>
#include <algorithm>
#include <cstring>
#define N 64

using namespace std;

bool st[N];
int sticks[N];
int n, sum, length;

bool dfs(int u, int len, int dx) // 当前木棒数量,当前木棒长度,当前木棍起始下标
{
if (u * length == sum) return true;
if (len == length) return dfs(u + 1, 0, 0);

for (int i = dx; i < n; ++ i)
{
int &l = sticks[i];

if (st[i] || len + l > length) continue;

st[i] = true;
if (dfs(u, len + l, i + 1)) return true;
st[i] = false;

//剪枝 第一根木棍失败则失败 || 最后一根木棍失败则失败
if (!len || l + len == length) return false;

// 剪枝 去除重复
int j = i + 1;
while (j < n && l == sticks[j]) ++ j;
i = j - 1;
}

return false;
}

// 总体思路,暴力dfs, 只要 sum % length == 0, 再dfs证明多组木棒是否等高,否则length++
int main()
{
while (cin >> n, n)
{
sum = length = 0;

for (int i = 0; i < n; ++ i)
scanf("%d", &sticks[i]), sum += sticks[i], length = max(length, sticks[i]);

// 从小到大排序会超时
sort(sticks, sticks + n, greater<int>());

memset(st, false, sizeof st);

while (true)
{
if (sum % length == 0 && dfs(0, 0, 0))
{
printf("%d\n", length);
break;
}
++ length;
}
}

return 0;
}
 评论