Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 132725 | Accepted: 31172 |
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
无论是后台数据还是需要的算法剪枝程度,真的是无法挑剔的一个题,剪枝无果,贪心WA,最终还是看的大牛题解找到了思路AC的。
重要剪枝:
1、一定是几根或者一根木棍组成大木棍,所以我们不必要从长度为1开始枚举,我们从最长的那根木棍开始枚举。
2、我们用pre标记,上一个建组的长度没有必要建组第二次。
3、组成的最终长度绝对是所有小木棍长度的和的因字数,所以枚举j的时候判断一下sum%j==0再进入dfs。
4、回溯的该跳出就跳出、
AC代码:(参考自http://blog.csdn.net/woshixingaaa/article/details/5589100)
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; int a[65]; int vis[65]; int s, j, n; bool cmp(int a, int b)//从大到小排序 { return a > b; } bool dfs(int sum, int k, int cont) { if (cont == s) return true;//达到目标 else if (sum == j) return dfs(0, 0, cont + 1);//拼成一根之后,拼下一根 else { int pre, i;//pre剪重复情况。 for (pre = 0, i = k; i < n; i++) { if (vis[i] && a[i] != pre && a[i] + sum <= j) { pre = a[i]; vis[i] = false; if (dfs(sum + a[i], i + 1, cont)) break; vis[i] = true; if (k == 0) return false;//如果回溯到这里,跳出这种情况。 } } if (i == n) return false; else return true; } } int main() { int i, sum; while(~scanf("%d",&n),n) { for (i = sum = 0; i<n; i++) { scanf("%d",&a[i]); sum += a[i]; } sort(a, a+ n,cmp); for (j = a[0]; j< sum; j++) { if(sum % j== 0) { s = sum / j; memset(vis, true,sizeof(vis)); if (dfs(0, 0, 0)) break; } } printf("%d\n",j); } }