问题描述:
有分别价值为1,2,3,4,5,6的6种物品,输入6个数字,表示相应价值的物品的数量,问一下能不能将物品分成两份,是两份的总价值相等,其中一个物品不能切开,只能分给其中的某一方,当输入六个0是(即没有物品了),这程序结束,总物品的总个数不超过20000
题目链接:POJ NO.1014
思路:
一道很经典的多重背包题目。
如果价值总和为奇数那么不可能平分,直接输出Can't be divided。
剩下的没什么好说的了代码交代的很清楚了。
PS:递推关系按照《挑战程序设计》来的,学习动态规划,一般人是不会一眼就看出端倪的,需要我们拿起纸和笔,把每一步(至少前3步)都写出来,这样会很有助于我们理解动态规划。
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<stack>
#include<cstring>
#include<string>
#include<vector>
#include<set>
using namespace std;
#define X first
#define Y second
#define PI 3.1415926
const int INF = 0x3f3f3f3f;
const int MAX = 3e5;
int dp[MAX];
int main(){
int arr[7], cnt = 1;
while(1){
int sum = 0;
for(int i = 1; i <= 6; i++){
scanf("%d", &arr[i]);
sum += arr[i] * i;
}
if(!sum) break;
if(sum % 2){
printf("Collection #%d:\n", cnt);
printf("Can't be divided.\n\n");
cnt++;
continue;
}
memset(dp, -1, sizeof(dp));
dp[0] = 0;
int k = sum / 2;
for(int i = 1; i <= 6; i++){
for(int j = 0; j <= k; j++){
if(dp[j] >= 0){
dp[j] = arr[i];
}else if(j < i || dp[j-i] <= 0){
dp[j] = -1;
}else{
dp[j] = dp[j-i] - 1;
}
}
}
if(dp[k] >= 0){
printf("Collection #%d:\n", cnt);
printf("Can be divided.\n\n");
}else{
printf("Collection #%d:\n", cnt);
printf("Can't be divided.\n\n");
}
cnt++;
}
return 0;
}