题目大意:
有六个大理石,他们的价值分别是1,2,3,4,5,6,然后分别给出六个大理石的个数,问如何平分给两个人,令两个人所得到的价值相等
典型的多重背包问题,
for(int i=1;i<=n;i++){//i种商品
cin>>v>>w>>s;
for(int j=m;j>0;j--){//容量为j的背包
for(int k=1;k<=s&&k*v<=j;k++)//k个i种商品
f[j]=max(f[j],f[j-k*v]+k*w);//状态转移方程
}
}
看数据范围,铁定超时的,所以我们来优化下,二进制优化的01背包,对于多重背包的暴力,我们可以只要优化,把13个数个物品分成,1,2,4,6这样的堆,我们就可以把多重背包问题转变成01背包问题,这是一裸题
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N =100010;
int f[N];
int v[N],w[N];
int n,m;
int main(){
cin>>n>>m;
int idx=1;
for(int i=1;i<=n;i++){
int a,b,c;
cin>>a>>b>>c;
int k;
for(k=1;k<=c;k<<1){//ki=1,2,4,8,.......
v[idx]=a*k;
w[idx]=b*k;
idx++;
c-=k;
}
if(c>0){//将剩余下的加入
v[idx]=a*c;
w[idx]=b*c;
idx++;
}
}
for(int i=1;i<idx;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[m]<<endl;
return 0;
}
传送门
这里要求恰好达到平分这个状态,也就是当背包大小是价值的一半恰好装满。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N =200010;
int f[N];
int dp[N];
int main(){
bool flag=false;
int sum,idx;
int t=1;
while(1){
sum=0;
flag=false;
idx=1;
memset(f,0,sizeof(f));
memset(dp,0,sizeof(dp));//每次都要初始数据
for(int i=1;i<=6;i++){
int a;
scanf("%d",&a);
if(a!=0)flag=true;
int j;
for( j=1;j<=a;j<<1){
dp[idx++]=j*i;
a-=j;sum+=j*i;
}
if(a>0)dp[idx++]=i*a,sum+=i*a;
}
if(!flag)break;
printf("Collection #%d:\n",t++);
if(sum%2)printf("Can't be divided.\n\n");
else {
int mid=sum/2;
for(int i=1;i<idx;i++)
for(int j=mid;j>=dp[i];j--)
f[j]=max(f[j],f[j-dp[i]]+dp[i]);
if(f[mid]==mid)printf("Can be divided.\n\n");
else printf("Can't be divided.\n\n");
}
}
return 0;
}