以前做过类似的题目,所以很快就有思路了。
首先判断marbles的总价值是否是偶数,如果不是的话,显然不能对半分。如果总价值是偶数,则变成背包问题,判断是否有marbles的组合的价值为总价值的一半。
第一次试,循环的上下界设的比较宽,超时了。然后想了一下,觉得可以做一些限制,把这些限制加了以后,就过了。
#includeusing namespace std;const int MAX_MARBLE = 20005;int ans[MAX_MARBLE * 6];/* marbles可能达到的最大价值是MAX_MARBLE * 6 */void readMarbles(int marbles[]){ for (int i = 1;i <= 6;i ++) scanf("%d",&marbles[i]);}int isExit(int marbles[]){ readMarbles(marbles); int isAllZero = 1; for (int i = 1;i <= 6;i ++) { if (marbles[i] != 0) { isAllZero = 0; break; } } return isAllZero;}int getTotal(int marbles[])/* 计算所有marbles之和 */{ int total = 0; for (int i = 1;i <= 6;i ++) total += marbles[i] * i; return total;}int main (){ int marbles[7]; int caseNum = 1; while (isExit(marbles) == 0)/* 读并判断是否结束 */ { printf("Collection #%d:\n",caseNum); caseNum ++; int total = getTotal(marbles); if (total % 2 != 0)/* 如果所有marbles之和不是偶数,肯定不能分成两半 */ { printf("Can't be divided.\n\n"); continue; } memset(ans,0,sizeof(ans)); ans[0] = 1; int maxPos = 0,lowerBound,upperBound; for (int i = 1;i <=6;i ++) { for (int k = 1;k <= marbles[i];k ++) { upperBound = (maxPos + i) < (total / 2) ? (maxPos + i) : (total / 2); if (k == 1)/* 第一次,从i开始查找 */ lowerBound = i; for (int j = upperBound;j >= lowerBound;j --) { if (ans[j - i] == 1) { ans[j] = 1; maxPos = maxPos > j ? maxPos : j;/* maxPos记录当前找到的marbles的最大价值 */ } } lowerBound = upperBound;/* upperBound以前的有效值都被找过了,下一次查找从upperBound开始 */ } if (ans[total / 2] == 1)/* 已经找到答案,提前结束 */ break; } if (ans[total / 2] == 1) printf("Can be divided.\n\n"); else printf("Can't be divided.\n\n"); } return 0;}