[POJ1011] 木棒 - DFS+剪枝

木棒
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 152862   Accepted: 36440

Description

乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。

Input

输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。

Output

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

Sample Input

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

Sample Output

6
5

Source

 

 
提交地址 POJ      LUOGU
 

 
题解 :
枚举长度, 长度必须可以整除总长度;
剪枝:
1) 从大到小排序。
2) 每次记录上次的木棍, 防止重复搜索,因为长度一样的下面的搜索树也一样,没必要走两次。
3) 如果在一根木棒中尝试拼接的第一根木棍的递归分支就以失败返回, 直接判断无解。
 

 
Code
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 int n, a[101], v[101], len, cnt, sum, val;
 8 bool cmp(int a, int b){return a > b;}
 9 
10 inline bool dfs(int stick, int cab, int last)
11 {
12     if (stick > cnt) return 1;
13     if (cab == len) return dfs(stick + 1, 0, 1);
14     int fail = 0;
15     for (register int i = last ; i <= n ; i ++)
16     {
17         if (!v[i] and cab + a[i] <= len and fail != a[i])
18         {
19             v[i] = 1;
20             if (dfs(stick, cab + a[i], i + 1)) return 1;
21             fail = a[i];
22             v[i] = 0;
23             if (cab == 0) return 0;
24         }
25     }
26     return 0;
27 }
28 
29 int main()
30 {
31     while (scanf("%d", &n) != EOF)
32     {
33         if (n == 0) return 0;
34         sum = 0, val = 0;
35         for (register int i = 1 ; i <= n ; i ++) {scanf("%d", &a[i]);sum+=a[i], val=max(val, a[i]);}
36         sort(a + 1, a + 1 + n, cmp);
37         for (len = val ; len <= sum ; len++)
38         {
39             if (sum % len) continue;
40             cnt = sum / len;
41             memset(v, 0, sizeof v);
42             if (dfs(1, 0, 1)) break;
43         }
44         printf("%d\n", len);
45     }
46     return 0;
47 }

猜你喜欢

转载自www.cnblogs.com/zZh-Brim/p/9163638.html