poj 1014多重背包

题意:给出价值为1,2,3,4,5,66种物品数量,问是否能将物品分成两份,使两份的总价值相等。

思路:求出总价值除二,做多重背包,需要二进制优化。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int n[7];
int v,sum;
bool flag;
int dp[100000];

/*完全背包*/
void CompletePack(int cost,int weight)
{
	for(int i=cost;i<=v;i++)
	{
		dp[i]=max(dp[i],dp[i-cost]+weight);
		if(dp[i]==v)    //剪枝
		{
			flag=true;
			return;
		}
	}

	return;
}
/*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[i]==v)    //剪枝
		{
			flag=true;
			return;
		}
	}
	return;
}

/*多重背包*/
void MultiplePack(int cost,int weight,int amount)
{
	if(cost*amount>=v)
	{
		CompletePack(cost,weight);
		return;
	}

	if(flag)    //剪枝
		return;

	/*二进制优化*/
	int k=1;
	while(k<amount)
	{
		ZeroOnePack(k*cost,k*weight);

		if(flag)
			return;

		amount-=k;
		k*=2;
	}
	ZeroOnePack(amount*cost,amount*weight);

	return;
}

int main(int i)
{
	int test=1;
	while(scanf("%d%d%d%d%d%d", &n[1], &n[2], &n[3], &n[4], &n[5], &n[6])!=EOF)
    {
		sum=0;  //物品总价值

		for(i=1;i<=6;i++)
			sum+=i*n[i];

		if(sum==0)
			break;

		if(sum%2)
		{
			cout<<"Collection #"<<test++<<':'<<endl;
			cout<<"Can't be divided."<<endl<<endl;
			continue;
		}

		v=sum/2;
		memset(dp,-1,sizeof(dp));
		dp[0]=0;
		flag=false;

		for(i=1;i<=6;i++)
		{
			MultiplePack(i,i,n[i]);

			if(flag)    //剪枝
				break;
		}

		if(flag)
		{
			cout<<"Collection #"<<test++<<':'<<endl;
			cout<<"Can be divided."<<endl<<endl;
			continue;
		}
		else
		{
			cout<<"Collection #"<<test++<<':'<<endl;
			cout<<"Can't be divided."<<endl<<endl;
			continue;
		}
		printf("
");
	}
	return 0;
}


 

原文地址:https://www.cnblogs.com/amourjun/p/5134115.html