简单题意
有分别价值为1,2,3,4,5,6的6种物品,每种价值物品有相对应的数量,问能否将物品分成两份,使得两份总价值相等。
解题思路形成过程
老师上课讲的例题,主要思想就是把一个多重背包问题,转化为01背包或完全背包来解决。用三个数组:c是费用,w是价值,m是数量,如果物品足够塞满背包转化为完全背包问题,否则转化为01背包问题。
感想
学会了一个套路,将多重背包问题,转换为01背包或完全背包的问题
AC代码
#include<iostream>
#include<stdio.h>
#include<fstream>
using namespace std;
const int INF=100000000;
int f[240005];//f[j]相当于f[i][j]: 考虑1...i个物品,恰好放到容量为j,所能达到的最大价值
int v; //背包容量
//处理一个完全背包(该种物品不限量)
void complete_pack(int *a,int c,int w)
{
for(int i=c;i<=v;i++)
a[i]=max(a[i],a[i-c]+w);
}
//处理一个 01背包 (该种物品只有一个)
void zeroone_pack(int *a,int c,int w)
{
for(int i=v;i>=c;i--)
a[i]=max(a[i],a[i-c]+w);
}
//处理一个多重背包 (该种物品指定上限)
void mutiple_pack(int *a,int c,int w,int m)
{
//该种物品足以塞满背包-->转化为完全背包
if(c*m>=v){
complete_pack(a,c,w);
return;
}
int k=1;
while(k<m)
{
zeroone_pack(a,k*c,k*w);
m=m-k;
k=2*k;
}
zeroone_pack(a,c*m,w*m);
}
int main(){
ifstream cin("in.txt");
freopen("in.txt","r",stdin);
int sum,c[7],w[7],m[7],cas=0;
while(cin>>m[1]>>m[2]>>m[3]>>m[4]>>m[5]>>m[6]&&(m[1]||m[2]||m[3]||m[4]||m[5]||m[6])){
sum=0;
for(int i=1;i<=6;i++){
c[i]=w[i]=i;
sum+=c[i]*m[i];
}
printf("Collection #%d:\n",++cas);
if(sum&1){
puts("Can't be divided.\n");
}else{
sum/=2;
v=sum;
for(int i=1;i<=sum;i++)
f[i]=-INF;
f[0]=0;
for(int i=1;i<=6;i++)
mutiple_pack(f,c[i],w[i],m[i]);//c是费用,w是价值,m是数量
if(f[v]<0){
puts("Can't be divided.\n");
}else{
puts("Can be divided.\n");
}
}
}
return 0;
}