题目描述:
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入输出格式输入格式:
输入文件共有二行。第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65(管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)第二行为N个用空个隔开的正整数,表示N根小木棍的长度。输出格式:输出文件仅一行,表示要求的原始木棍的最小可能长度
输入输出样例
输入样例#1:95 2 1 5 2 1 5 2 1
输出样例#1:6
---------------------------
各种剪枝
基本思路:
从小到大遍历原来木棍可能的长度
把木棍排序,按从大到小的顺序填入原来的木棍中.
具体剪枝直接看代码
#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; const int maxN = 65; int n; int a[maxN]; int vis[maxN]; int DFS(int lim, int len, int cnt, int last) { if(len == lim) len = 0, last = n - 1; if(cnt == n) return 1; int flag = 0; for(int i = last; i >= 0; i --) //last用于剪枝 if(! vis[i] && a[i] + len <= lim) { if(i < n - 1 && a[i] == a[i + 1] && ! vis[i + 1]) //剪枝 continue; vis[i] = 1; if(DFS(lim, len + a[i], cnt + 1, i)) return 1; vis[i] = 0; if(len == 0 || a[i] == lim - len) //剪枝.对于一个原长度,假如它是可行的 //则当其为空的时候,第一位无论填入什么,都应该是可以成立的.假如第一位填入的就不成立,可直接退出 //假如当前长度等于剩余长度且不可行,则其后的填法肯定都不可行 return 0; } return 0; } int main() { scanf("%d", &n); int sum = 0; for(int i = 0; i < n; i ++) { scanf("%d", &a[i]); if(a[i] > 50) i --, n --; else sum += a[i]; } sort(a, a + n); for(int i = a[1]; i <= sum / 2; i ++) if(sum % i == 0) //剪枝 { memset(vis, 0, sizeof(vis)); if(DFS(i, 0, 0, n - 1)) { printf("%d", i); return 0; } } printf("%d", sum); }