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