题意:
有6种物品,价值分别为1,2,3,4,5,6。数量分别为n1,n2,n3,n4,n5,n6(由输入决定)。请你判断能否把这些物品分成两份,使两份的价值相等。
输入为n1~n6,输出能否均分,当输入0 0 0 0 0 0 结束程序。
Sample Input
1 0 1 2 0 0 1 0 0 0 1 1 0 0 0 0 0 0
Sample Output
Collection #1: Can't be divided. Collection #2: Can be divided.
思路:
这是一道多重背包的问题,最近在看《背包九讲》,可以直接套用里面的模型,也可以自己把它转化为01背包问题。
另外優YoU http://blog.csdn.net/lyy289065406/article/details/6661449,大神给出了一个DFS解法,虽然能够在POJ上0MS AC,但是0 0 3 0 5 1这个测试数据却过不了。我自己写的DFS解法超时,应该有不超时的DFS,要好好想想!
源代码:
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
const int MAX = 60000;
const int NINF = -(1<<30);
int n[7];
int v;
int dp[MAX+1];
int flag; //完成的标志
int max(int a,int b)
{
return a>b?a:b;
}
//01背包
void ZeroOnePack(int cost,int weight)
{
for(int i = v;i >= cost;i--)
{
dp[i] = max(dp[i],dp[i-cost]+weight);
if(dp[v] == v) //满足结束条件
{
flag = 1;
return;
}
}
}
//多重背包
//为什么我只用 01背包 比 01背包+多重背包混合 更快?
void MultiplePack(int cost,int weight,int amount)
{
int k = 1;
while(k < amount)
{
ZeroOnePack(k*cost,k*weight);
if(flag)
return;
amount -= k;
k *= 2;
}
ZeroOnePack(amount*cost,amount*weight);
}
int main()
{
int test = 1;
int end;
int i;
while(1)
{
end = 1;
v = 0;
flag = 0;
for(i = 1;i <= 6;i++)
{
cin>>n[i];
if(n[i]) end = 0;
v += i*n[i];
}
if(end) break;
printf("Collection #%d:\n",test++);
if(v%2) //和是奇数
{
printf("Can't be divided.\n\n"); //一定要注意还要空出一行
continue;
}
v /= 2; //每一份的值
memset(dp,0,sizeof(dp));
for(i = 1;i <= 6;i++)
{
MultiplePack(i,i,n[i]);
if(flag)
break;
}
if(flag)
printf("Can be divided.\n\n");
else printf("Can't be divided.\n\n");
}
return 0;
}