题意:n种物品,每种物品的钱数及个数,问分成两份,使两份价值差最小。输出两份物品的价值。
背包容量为所有物品总价值和的一半,所能达到的最大价值就是其中的一种物品。另一种一减就是了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,sum,value[60],numb[60],dp[1000000];
void complete(int cost,int v){
for(int j=cost;j<=v;j++){
if(dp[j-cost]){
dp[j]=1;
}
}
}
void zeroone(int cost,int v){
for(int j=v;j>=cost;j--){
if(dp[j-cost]){
dp[j]=1;
}
}
}
int main(){
while(scanf("%d",&n)&&n>=0){
sum=0;
for(int i=1;i<=n;i++){
scanf("%d%d",&value[i],&numb[i]);
sum+=value[i]*numb[i];
}
int cy=sum/2;
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=1;i<=n;i++){
if(value[i]*numb[i]>=cy){
complete(value[i],cy);
}
else{
int amount=numb[i],ki=1;
while(ki<amount){
zeroone(value[i]*ki,cy);
amount-=ki;
ki*=2;
}
zeroone(value[i]*amount,cy);
}
}
int j=cy;
while(dp[j]==0){
j--;
}
cy=sum-j;
int mi=cy<j?cy:j,ma=cy>j?cy:j;
printf("%d %d\n",ma,mi);
}
return 0;
}
还有一种代码,开个辅助数组,来记录某种物品使用数量,来保证不会超过numb[i].使背包变为完全背包。
#include<cstdio>
using namespace std;
const int mm=222222;
const int mn=55;
int t[mm],v[mn],numb[mn];
bool f[mm];
int i,j,k,n,m,sum;
int main()
{
while(scanf("%d",&n),n>=0)
{
for(sum=i=0;i<n;++i)scanf("%d%d",&v[i],&numb[i]),sum+=v[i]*numb[i];
m=sum>>1;
for(i=f[0]=1;i<=m;++i)f[i]=0;
for(i=0;i<n;++i)
{
for(j=0;j<=m;++j)t[j]=0;
for(j=v[i];j<=m;++j)
if(!f[j]&&f[k=j-v[i]]&&t[k]<numb[i])t[j]=t[k]+1,f[j]=1;
}
while(!f[m])--m;
printf("%d %d\n",sum-m,m);
}
return 0;
}