/*
多重背包问题
该题求的是能否拿到总价值的一半
可以假设 每个球消耗的空间和它的价值相等
则本题可转化为:在总空间一半的口袋里能否得到总价值的一半(因为价值密度为1,故最多能达到一半)
*/
#include<stdio.h>
#include<string.h>
int d[120000],n[7],w;
void cpack(int c,int ww)
{
int j;
for(j=c;j<=w;j++)
{
if((d[j-c]+ww)>d[j])
d[j]=d[j-c]+ww;
}
}
void znpack(int c,int ww)
{
int j;
for(j=w;j>=c;j--)
{
if(d[j]<(d[j-c]+ww))
d[j]=d[j-c]+ww;
}
}
void mpack(int c,int ww,int nn)
{
if(c*nn>=w)
{
cpack(c,ww);
return;
}
int k=1;
while(k<nn)
{
znpack(k*c,k*ww);
nn=nn-k;
k=k*2;
}
znpack(nn*c,nn*ww);
}
int main()
{
int q=1,i;
while(1)
{
w=0;
for(i=1;i<=6;i++)
{
scanf("%d",&n[i]);
w+=i*n[i];
}
if(!w)
break;
if(w%2)
{
printf("Collection #%d:\nCan't be divided.\n\n",q++);
continue;
}
w=w/2;
d[0]=0;
memset(d,0,sizeof(d));
for(i=1;i<=6;i++)
{
if(!n[i])
continue;
mpack(i,i,n[i]);
}
if(d[w]!=w)
printf("Collection #%d:\nCan't be divided.\n\n",q++);
else printf("Collection #%d:\nCan be divided.\n\n",q++);
}
return 0;
}
以上是我仿别人的,我原先自己写的因为数组开小了,系统给了个Runtime Error(ACCESS_VIOLATION),同时没有把球消耗的空间假设为同它的价值,所以只能求:占用总数一半的价值,最多(或最少,最少可以将数组初始化为正无穷,不用判断数据是否合法)能拿到几个球;若d[一般价值]=初始化,则不可以平分。因此,处理比较复杂。
#include<stdio.h>
int d[120000],n[7],w;
void cpack(int c,int ww)
{
int j;
for(j=c;j<=w;j++)
{
if((d[j-c]+ww)<d[j])
d[j]=d[j-c]+ww;
}
}
void znpack(int c,int ww)
{
int j;
for(j=w;j>=c;j--)
{
if(d[j]>(d[j-c]+ww))
d[j]=d[j-c]+ww;
}
}
void mpack(int c,int ww,int nn)
{
if(c*nn>=w)
{
cpack(c,ww);
return;
}
int k=1;
while(k<nn)
{
znpack(k*c,k*ww);
nn=nn-k;
k=k*2;
}
znpack(nn*c,nn*ww);
}
int main()
{
int q=1,i;
while(1)
{
w=0;
for(i=1;i<=6;i++)
{
scanf("%d",&n[i]);
w+=i*n[i];
}
if(!w)
break;
if(w%2)
{
printf("Collection #%d:\nCan't be divided.\n\n",q++);
continue;
}
w=w/2;
d[0]=0;
for(i=1;i<=w;i++)
d[i]=999999999;
for(i=1;i<=6;i++)
mpack(i,1,n[i]);
if(d[w]==999999999)
printf("Collection #%d:\nCan't be divided.\n\n",q++);
else printf("Collection #%d:\nCan be divided.\n\n",q++);
}
return 0;
}