乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度
标签:
Description
Input
Output
Sample Input
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
Sample Output
6 5
Source
中文题意
首先把小木棍长度从大到小排序, 从最长的木棍aim开始搜, 如果这些木棍的总长度能够整除该木棍aim的长度,就开始递归搜。
能够拼成的根数为sum/aim, 如果成功则输出当前的长度。如果能匹配成功retrun true,否则return false。
同时标记搜过的木棍, 如果不可以则取消标记。
如果当前木棍不可以, 那么和改木棍相同长度的木棍也不可用 (剪枝)。
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; const int MAXN = 70; int n, sum, aim, num, a[MAXN]; bool used[MAXN]; bool cmp(int a, int b){//从大到小排序 return a > b; } bool dfs(int Stick, int len, int pos) {//Stick 当前组好的数目 len 组好的长度 pos 搜索到第几根 bool sign = (len == 0 ? true:false); if(Stick == num) return true;//全部完成搜索, 退出函数 for(int i = pos + 1; i < n; i++) { if(used[i]) continue;//当前的棍子不能再用了 if(len + a[i] == aim) {//正好可以和当前的棍子组成目标长度 used[i] = true; if(dfs(Stick+1, 0, -1)) return true;//进入下一层搜索 used[i] = false;//回溯 return false; } else if(len + a[i] < aim) {//长度不够 used[i] = true; if(dfs(Stick, len + a[i], i)) return true;//进入下一层搜索, 棍子长度变成 len + a[i] used[i] = false; //关键一步, 没有选择任何木棍, 跳出循环 if(sign) return false; while(a[i] == a[i+1]) i++;//剪枝 } } return false; } int main() { scanf("%d", &n); sum = 0; for(int i = 0; i < n; i++) { scanf("%d", &a[i]); sum += a[i];//求出所有木棍的总长度 } sort(a, a+n, cmp);//排序 for(aim = a[0]; aim <= sum; aim++) { if(sum % aim == 0) { num = sum/aim; memset(used, false, sizeof(used));//初始化 if(dfs(1, 0, -1)) { printf("%d\n", aim);//直接输出答案 break; } } } return 0; }
还是比较不错滴
标签:
原文地址:http://www.cnblogs.com/cshg/p/5768070.html