hdu 1059 Dividing

1.题目

http://acm.hdu.edu.cn/showproblem.php?pid=1059

2.分析

1.本题要求评分物品,所以资源上限应该为总价值的一半;
2.为了要达到价值的一半而进行物品的选择,可以按照01背包的思路针对每类物品的每一个商品进行01背包,记录中间产生的值并与资源限制进行比较,则题目可解;
3.但是01背包速度较慢,没有优化,详见《背包九讲》。

注释:由于不是要完全都选择,只是选择其中的部分,可以对每一类物品使用多重背包来搞即可,同时可以利用多重背包的优化策略,即使用多重背包来解决题目。

3.复杂度

第i种物品分成了O(log n[i])种物品,将原问题转化为了复杂度为O(V*Σlog n[i])的01背包问题

4.涉及内容

算法:动态规划

5.感想

应该对于题目进行深入分析,当感觉和某经典题目相似的时候,可以作为一种尝试先按照该思路进行解题

6.代码

#include <iostream>
using namespace std;
int c1059[7],f1059[60005];
long total1059=0,limitvalue1059=0,num1059=0;
bool cin1059()
{
	memset(c1059,0,sizeof(c1059));
	memset(f1059,0,sizeof(f1059));
	total1059=limitvalue1059=0;
	cin>>c1059[1]>>c1059[2]>>c1059[3]>>c1059[4]>>c1059[5]>>c1059[6];
	for(int i=6;i>=1;--i)
	{
		total1059+=c1059[i]*i;
	}
	return (c1059[1]||c1059[2]||c1059[3]||c1059[4]||c1059[5]||c1059[6]);
}

int max1059(int a,int b) { return a>b?a:b; }

void ZeroOnePack1059(int c,int w)//01背包问题
{
	for(int i=limitvalue1059;i>=c;--i)
		f1059[i]=max1059(f1059[i],f1059[i-c]+w);
}

void CompletePack1059(int c,int w)//多重背包问题
{
	for(int i=c;i<=limitvalue1059;++i)
		f1059[i]=max1059(f1059[i],f1059[i-c]+w);
}

void MultiplePack1059(int c,int w,int n)//完全背包问题
{
	if(c*n>=limitvalue1059)
	{
		CompletePack1059(c,w);
	}
	else
	{
		int k=1;
		while(k<n)
		{
			ZeroOnePack1059(c*k,w*k);
			n-=k;//一下两条语句的顺序很重要
			k+=k;
		}
		ZeroOnePack1059(c*n,w*n);
	}
}

int main()
{
	//freopen("in.txt","r",stdin);
	while(cin1059())
	{
		if(total1059%2)
		{
			cout<<"Collection #"<<++num1059<<":"<<endl<<"Can't be divided."<<endl<<endl;
			continue;
		}
		limitvalue1059=total1059/2;
		for(int i=1;i<=6;++i)
		{
			MultiplePack1059(i,i,c1059[i]);
		}
		if(f1059[limitvalue1059]==limitvalue1059)
			cout<<"Collection #"<<++num1059<<":"<<endl<<"Can be divided."<<endl<<endl;
		else
			cout<<"Collection #"<<++num1059<<":"<<endl<<"Can't be divided."<<endl<<endl;
	}
	return 0;
}

7.参考文献

1.《背包九讲》
2.http://www.cnblogs.com/zhourongqing/archive/2012/08/01/2619011.html
3.http://java-mans.iteye.com/blog/1646457
4.http://blog.csdn.net/shahdza/article/details/6311504

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值