POJ1011 Sticks
木棒
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 147267 | Accepted: 34890 |
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
Translator
北京大学程序设计实习, Xie Di
【题解】
搜索思路:枚举最终的木棒长度len,计算出木棒的根数cnt,依次搜索每根木棒由哪些木棍组成。
剪枝一(搜索顺序):木棍长度从大到小排序,先尝试长的木棍,同时每根木棒上的木棍也应该是按照长度递减的
剪枝二(枚举可行性):从小到大枚举最终木棒长度,只有该长度是长度总和的约数时才进行搜索
剪枝三(重复冗余剪枝):记录当前刚搜完的木棍长度,若搜索失败,当前木棒不再尝试同样长度的其它木棍
剪枝四(搜索可行性):如果在一个尚未包含任何木棍的木棒中,尝试搜索当前最长的木棍失败,直接返回。
——by 李煜东
实验证明这四个剪枝缺一不可(mmp)
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cstdio> 5 #include <algorithm> 6 #define max(a, b) ((a) > (b) ? (a) : (b)) 7 8 inline void read(int &x) 9 { 10 x = 0;char ch = getchar(), c = ch; 11 while(ch < '0' || ch > '9')c = ch, ch = getchar(); 12 while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); 13 if(c == '-')x = -x; 14 } 15 16 const int INF = 0x3f3f3f3f; 17 const int MAXN = 5000 + 5; 18 19 int n,num[MAXN],len,sum,b[MAXN],cnt[MAXN],ma,step; 20 21 //到第now根,最后一个长度是num[last] - 1 22 int dfs(int now, int last) 23 { 24 if(now > step)return 1; 25 if(cnt[now] == len)return dfs(now + 1, 1); 26 int pre = 0; 27 for(register int i = last;i <= n;++ i) 28 { 29 if(b[i] || cnt[now] + num[i] > len || num[pre] == num[i])continue; 30 cnt[now] += num[i],b[i] = 1; 31 if(dfs(now, i + 1))return 1; 32 cnt[now] -= num[i],b[i] = 0; 33 pre = i; 34 if(cnt[now] == 0)return 0; 35 } 36 return 0; 37 } 38 39 int main() 40 { 41 for(;;) 42 { 43 memset(cnt,0,sizeof(cnt)),sum=0,len=0,memset(b,0,sizeof(b)),ma = 0; 44 read(n); 45 if(!n)break; 46 for(register int i = 1;i <= n;++ i) 47 read(num[i]), sum += num[i], ma = max(ma, num[i]); 48 std::sort(num + 1, num + 1 + n, std::greater<int>()); 49 for(len = ma;len <= sum;++ len) 50 { 51 if(sum % len)continue; 52 step = sum/len; 53 if(dfs(1, 1)) 54 { 55 printf("%d\n", len); 56 break; 57 } 58 } 59 } 60 return 0; 61 }