Problem Description
George有一些长度相等的木棒,他随意的将这些木棒切成长度最多是50的小木棒。麻烦来了,他现在想将这些杂乱的小木棒恢复到原来的木棒,但是他忘记了原来到木棒的数量和长度。请你帮助他设计一个程序计算出原来木棒可能的最小长度,所有小木棒的长度均表示为大于0的整数。
Input
每组输入数据包括两行。第一行是George切后小木棒的个数,最多有64根小木棒;第二行是这些小木棒的长度,这些长度表示为空格分开的整数。输入样例以整数0表示结束。
Output
输出一行,即为原始木棒可能的最小长度。
Sample Input
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0Sample Output
6 5
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int a[105], n, now; bool vis[105]; bool dfs(int len, int cnt, int p){ //当前需要的木棍长度,当前已拼接的木棍个数,当前拼接的下标 if(cnt == n) return true; //已经拼成了n个木棍,可行 if(len == 0) { //当前需要的木棍长度为0 len = now; //把len置为当前检测长度 now p = n; //把搜索下标置为最大 } int lst = 0; for(int i=p-1; i>=0; i--){ //剪枝:再同一根木棍的拼凑中,不用反复搜索较大木棍,[0, p] if(!vis[i] && a[i] <= len && a[i] != lst){ //剪枝:如果和上一个不可行长度相等,则跳过 vis[i] = true; // 取当前木棍 再搜索 if(dfs(len - a[i], cnt + 1, i)) // 可行 return true return true; vis[i] = false; // 不可行,则需要回退状态,不选当前木棍 lst = a[i]; // 记录上一个不可行的木棍,和这个相等的都不用判 if(len == now) return false; // 剪枝: 如果有任何一个不能构成len长度,则return false } } return false; } int main(){ int maxx, sum, ans; // 分别记录最长的木棍,总长度,答案 while(~scanf("%d", &n) && n){ sum = 0; for(int i=0; i<n; i++) { scanf("%d", &a[i]); sum += a[i]; } sort(a, a+n); //sort 默认升序排序 maxx = a[n-1]; //取最大的元素 ans = sum; //ans初始化为sum,如果[maxx, sum/2]范围内都找不到解,一定是全部合成一根 for(int i=maxx; i<=sum/2; i++){ //剪枝:如果[maxx, sum/2]范围内都找不到解,答案是sum if(sum%i == 0) { //剪枝:当i是sum的因子,才有可能是原木棍长度 memset(vis, 0, sizeof vis); //每次搜索前,把所有木棍置为未选择状态 now = i; //当前搜索的目标长度是i if(dfs(i, 0, n)) { ans = i; //剪枝:找到的第一组可行解直接跳出 break; } } } printf("%d\n", ans); } return 0; }