题意:有一些价值1~6的大理石,分别给出价值为1~6的大理石的数量,问能否分成价值相等的两堆。
解法:dfs+剪枝,也可以是二进制优化的多重背包。
只要看能否搜到总价值的一半就可以了。
看了一些博客总结了几个剪枝(如果我理解的有错误希望有大神指正orz):
- 当总价值为奇数时一定不能分成两堆。
- 优先选值比较大的能更快凑出答案。
- 回溯的时候不将用过的大理石加回来,对此我的理解是如果能凑出两堆那么一定会有几个小块的大理石去代替它。
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #include<limits.h> #include<time.h> #include<stdlib.h> #include<map> #include<queue> #include<set> #include<stack> #include<vector> #define LL long long using namespace std; int sum, halfsum; int a[6]; bool dfs(int value, int pre) { if(value == halfsum) return true; for(int i = pre; i >= 0; i--)//第二个剪枝 { if(a[i]) { if(value + (i + 1) <= halfsum) { a[i]--; if(dfs(value + (i + 1), i)) return true; //a[i]++;//第三个剪枝 } } } return false; } int main() { int cse = 1; while(~scanf("%d", &a[0])) { sum = a[0]; for(int i = 1; i < 6; i++) { scanf("%d", &a[i]); sum += a[i] * (i + 1); } if(sum == 0) break; printf("Collection #%d: ", cse++); if(sum & 1)//第一个剪枝 { printf("Can't be divided. "); continue; } halfsum = sum / 2; if(dfs(0, 5)) printf("Can be divided. "); else printf("Can't be divided. "); } return 0; }