木棒
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
题解 :
枚举长度, 长度必须可以整除总长度;
剪枝:
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 }