题目:http://acm.hdu.edu.cn/showproblem.php?pid=1059
题意:质量为i的东西有a[i]个,分两拨问能不能质量相等,质量和为奇显然不能,偶数时只要达到sum/2的背包就行了,剩下的自然组成了另外sum/2的背包。
多重背包:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=200005;
int a[7],dp[maxn];
int main(){
int cnt=0;
while(cin>>a[1]>>a[2]>>a[3]>>a[4]>>a[5]>>a[6]){
memset(dp,0,sizeof(dp));
cnt++;
int sum=0;
for(int i=1;i<=6;i++)
sum+=a[i]*i;
if(sum==0)
break;
if(sum%2==1){
printf("Collection #%d:\nCan't be divided.\n",cnt);
continue;
}
sum/=2;
for(int i=1;i<=6;i++)
for(int j=1;j<=a[i];j++)
for(int k=sum;k>=i;k--)
dp[k]=max(dp[k],dp[k-i]+i);
if(dp[sum]==sum)
printf("Collection #%d:\nCan be divided.\n",cnt);
else
printf("Collection #%d:\nCan't be divided.\n",cnt);
}
return 0;
}
显然超时了,多重背包分成了好多的1个01背包,然而可以用二进制分,这样需要几个都可以加出来。比如13分成1,2,4,6,需要5个的话拿1,4就行。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int a[7],dp[maxn],w[maxn];
int main(){
int cnt=0;
while(cin>>a[1]>>a[2]>>a[3]>>a[4]>>a[5]>>a[6]){
memset(dp,0,sizeof(dp));
memset(w,0,sizeof(w));
cnt++;
int sum=0;
for(int i=1;i<=6;i++)
sum+=a[i]*i;
if(sum==0)
break;
if(sum%2==1){
printf("Collection #%d:\nCan't be divided.\n\n",cnt);
continue;
}
sum/=2;
int cnt0=1;
for(int i=1;i<=6;i++){
for(int j=1;j<=a[i];j<<=1){
w[cnt0++]=j*i;
a[i]-=j;
}
if(a[i]>0) //把最后剩余的那个拆出来
w[cnt0++]=a[i]*i;
}
for(int i=1;i<=cnt0;i++)
for(int j=sum;j>=w[i];j--)
dp[j]=max(dp[j-w[i]]+w[i],dp[j]);
if(dp[sum]==sum)
printf("Collection #%d:\nCan be divided.\n\n",cnt);
else
printf("Collection #%d:\nCan't be divided.\n\n",cnt);
}
return 0;
}
然而这种跟poj 2392一样的做法是最快的,一种一种的往里放,在数量和价值的条件下,一点一点加,看能达到的最大高度。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int a[7],f[maxn],num[maxn];
int main(){
int cnt=0;
while(cin>>a[1]>>a[2]>>a[3]>>a[4]>>a[5]>>a[6]){
memset(f,0,sizeof(f));
memset(num,0,sizeof(num));
cnt++;
int sum=0,ans=0;;
for(int i=1;i<=6;i++)
sum+=a[i]*i;
if(sum==0) break;
if(sum%2==1){
printf("Collection #%d:\nCan't be divided.\n\n",cnt);
continue;
}
sum/=2;
f[0]=1;
for(int i=1;i<=6;i++){
memset(num,0,sizeof(num));
for(int j=i;j<=sum;j++)
if(!f[j]&&f[j-i]&&num[j-i]+1<=a[i]){
f[j]=1;
num[j]=num[j-i]+1;
ans=max(ans,j);
}
}
if(ans==sum)
printf("Collection #%d:\nCan be divided.\n\n",cnt);
else
printf("Collection #%d:\nCan't be divided.\n\n",cnt);
}
return 0;
}