终于学到了用二进制的多重背包,:)其实也不是那么难嘛
题意:
现在有价值从1到6的物品,并且告诉每种价值的物品有多少种,然后问你能否把物品分成两堆,然后每堆的价值都是总价值的一半。
思路:
恩,就是一道多重背包题,但是这里要用到二进制优化,否则的话就会T掉。
(二进制优化后的背包的价值和重量都是系数乘上原来的那个)
其实多重背包的实质就是一个01背包,因为我们只要把每种价值的所有数量的物品存进去就好了,然后就像01背包一样做就好了。但是如果每次只减1的话,时间复杂度太高了,所以我们使用二进制优化,比如对于13的数量,我们拆成1,2,4,6。这样就能把复杂度给优化了。
//还有一点就是能够用位运算的话,就尽量用位运算。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 20010
#define inf 99999999
int n[10];
int dp[120010],v[120010],w[120010];
int main(){
int jj=1;
while(~scanf("%d%d%d%d%d%d",&n[1],&n[2],&n[3],&n[4],&n[5],&n[6])){
if(n[1]==n[2]&&n[2]==n[3]&&n[3]==n[4]&&n[4]==n[5]&&n[5]==n[6]&&n[1]==0) break;
memset(dp,0,sizeof(dp));
memset(v,0,sizeof(v));
memset(w,0,sizeof(w));
int sum=0;
for(int i=1;i<=6;i++) sum+=n[i]*i;
if(sum%2){
printf("Collection #%d:\n",jj++);
printf("Can't be divided.\n");
}
else{
int num=0;
for(int i=1;i<=6;i++){
int c=n[i];
for(int k=1;k<=c;k=k<<1){
w[num]=i*k;
v[num]=i*k;
num++;
c=c-k;
}
if(c>0){
w[num]=i*c;
v[num]=i*c;
num++;
}
}
int mid=sum/2;
for(int i=0;i<num;i++){
for(int j=mid;j>=0;j--){
if(j>=w[i]) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
if(dp[mid]==mid){
printf("Collection #%d:\n",jj++);
printf("Can be divided.\n");
}
else{
printf("Collection #%d:\n",jj++);
printf("Can't be divided.\n");
}
}
printf("\n");
}
}