您的位置:首页 > 其它

暑假- 动态规划 I-(T - Dividing)

2015-07-22 20:44 309 查看
/*
本题与N - Coins相似。把6种大理石看成6种硬币。判断能否由这个硬币凑成总和的一半[平均分为2份]
多重背包:转换成01背包和完全背包
*/
#include<iostream>
#include<algorithm>
using namespace std;
int marbles[8];
int dp[220000];//因为只有6种大理石,每种数目最多为20000,则总为(1+2+3+4+5+6)*20000
               //再除以2就是dp数组的最大值。
int mymax(int a,int b)
{
	return a>b?a:b;
}
void CompletePack(int v,int m)
{
	for(int i=v;i<=m;i++)
	{
		dp[i]=mymax(dp[i],dp[i-v]+v);
	}
}
void ZeroOnePack(int v,int m)
{
	for(int i=m;i>=v;i--)
	{
		dp[i]=mymax(dp[i],dp[i-v]+v);
	}
}
void MuiltPack(int v,int c,int m)
{
	if(v*c>=m)
	{
		CompletePack(v,m);
	}
	else
	{
		int k=1;
		while(c-k>=0)
		{
			ZeroOnePack(v*k,m);
			c-=k;
			k*=2;
		}
		ZeroOnePack(v*c,m);
	}
}
int main()
{
	int ans=0;
	while(1)
	{
		ans++;
		int sum=0;
		memset(marbles,0,sizeof(marbles));
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=6;i++)
		{
			cin>>marbles[i];
			sum+=marbles[i]*i;//sum记录总价子
		}
		if(!(marbles[1]||marbles[2]||marbles[3]||marbles[4]||marbles[5]||marbles[6]))
		{   //结束条件
			break;
		}
		if(sum%2!=0)//如果不能平分。
		{
			cout<<"Collection #"<<ans<<":"<<endl;
			cout<<"Can't be divided."<<endl;
			cout<<endl;
			continue;
		}
		sum=sum/2;
		for(int i=1;i<=6;i++)
		{
			if(!marbles[i])//面值为i的硬币数量为0。
			{
				continue;
			}
			MuiltPack(i,marbles[i],sum);
		}
		if(dp[sum]==sum)//如果可以由这些硬币凑成总价值的一半。
		{
			cout<<"Collection #"<<ans<<":"<<endl;
			cout<<"Can be divided."<<endl;
			cout<<endl;
		}
		else
		{
			cout<<"Collection #"<<ans<<":"<<endl;
			cout<<"Can't be divided."<<endl;
			cout<<endl;
		}
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: