木棒
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 136132 | Accepted: 32036 |
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
方法:DFS+强剪枝
分析:经典的搜索问题,需要细细考虑剪枝条件,每一次的剪枝都能大幅度提升速度。
剪枝:
1. 首先将数据从大到小排序,搜索的时候从大到小搜索,这样才能保证数据的充分使用,而且对剪枝也很有帮助
2. 原始每根木条的长度是总长度的约数,所以搜索空间是总长度的约数
3. 检索的时候,用最长木条的长度作为搜索的起始长度
4. 如果stick[i] == stick[i+1],且stick[i]匹配失败,那么stick[i+1]必然也是失败的
5. 如果第i组的第一根木条(也是最长的)在匹配过程中失败,那么就直接返回第i-1组重新匹配。因为第i组的组合一定是最长木条的子集。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #define MAX_NUM 64 6 #define FAILURE 1 7 #define SUCCESS 0 8 9 int gwStickNum = 1; 10 int gwtotalLen; 11 int gwData[MAX_NUM]; 12 int gwSelect[MAX_NUM]; 13 int gwGroup; 14 15 void sort(int *a, int left, int right) 16 { 17 if(left >= right) 18 { 19 return; 20 } 21 int i = left; 22 int j = right; 23 int key = a[left]; 24 while(i < j) 25 { 26 while(i<j && key>=a[j]) 27 { 28 j--; 29 } 30 a[i] = a[j]; 31 while(i<j && key<=a[i]) 32 { 33 i++; 34 } 35 a[j] = a[i]; 36 } 37 a[i] = key; 38 sort(a, left, i-1); 39 sort(a, i+1, right); 40 } 41 42 int match(int goal, int sum, int nowGroup) 43 { 44 int i = 0; 45 if(sum > goal) return FAILURE; 46 if(sum == goal) 47 { 48 nowGroup++; 49 if(nowGroup == gwGroup) return SUCCESS; 50 sum = 0; 51 return match(goal, sum, nowGroup); 52 } 53 for(i=1; i<gwStickNum; i++) 54 { 55 if(gwSelect[i] == 1) continue; 56 sum += gwData[i]; 57 gwSelect[i] = 1; 58 if(SUCCESS == match(goal, sum, nowGroup)) return SUCCESS; 59 gwSelect[i] = 0; 60 sum -= gwData[i]; 61 if(sum == 0) return FAILURE; 62 while(gwData[i] == gwData[i+1] && i < gwStickNum) 63 { 64 i++; 65 } 66 } 67 return FAILURE; 68 } 69 70 int searchFactors(int start) 71 { 72 int i = 0; 73 for(i=start+1; i<=gwtotalLen; i++) 74 { 75 if(gwtotalLen % i ==0) return i; 76 } 77 return 0; 78 } 79 80 int calc() 81 { 82 int sum = gwData[0]; 83 int Len = 0; 84 gwSelect[0] = 1; 85 int start = gwData[0]-1; 86 while(start < gwtotalLen) 87 { 88 Len = searchFactors(start); 89 gwGroup = gwtotalLen / Len; 90 if(SUCCESS == match(Len, sum, 0)) return Len; 91 start = Len; 92 memset(gwSelect, 0, sizeof(gwSelect)); 93 gwSelect[0] = 1; 94 sum = gwData[0]; 95 } 96 return 0; 97 } 98 99 int getTatolLen(int *a, int arryLen) 100 { 101 int i = 0; 102 int sum = 0; 103 for(i=0; i<arryLen; i++) 104 { 105 sum += a[i]; 106 } 107 return sum; 108 } 109 110 int main(void) 111 { 112 int i = 0; 113 int result = 0; 114 while(scanf("%d", &gwStickNum), gwStickNum != 0) 115 { 116 for(i=0; i<gwStickNum; i++) 117 { 118 scanf("%d", &gwData[i]); 119 } 120 121 gwtotalLen = getTatolLen(gwData, gwStickNum); 122 sort(gwData, 0, gwStickNum-1); 123 result = calc(); 124 125 printf("%d\n", result); 126 memset(gwSelect, 0 , sizeof(gwSelect)); 127 } 128 129 return 0; 130 }
测试数据:
9
15 3 2 8 8 4 11 8 1
0
20
------------------------------------------------------
27
15 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8
0
20
------------------------------------------------------
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
6
5
------------------------------------------------------
46
40 37 32 10 47 4 42 56 61 23 59 36 27 16 16 37 26 19 14 29 31 58 51 32 63 28 11 25 12 15 39 42 46 43 11 19 53 17 39 21 45 44 8 23 51 55
58
57 6 44 4 16 35 54 9 32 23 43 55 46 41 8 41 55 44 31 59 57 58 59 29 53 30 3 39 52 17 32 45 8 40 34 18 20 11 32 33 14 41 31 25 4 42 54 9 29 37 47 29 34 20 47 56 61 5
26
3 64 18 49 4 40 18 61 50 36 17 49 8 17 62 11 24 8 36 59 34 26 28 7 37 26
0
89
89
99