思路:就是将多重背包问题转化成01背包
比如 v,w,s是1 2 3 时,就可以将这3个物品简化成2个 v,w 分别是 1 2 和2 4 的物品
将所有的物品简化完之后,问题就变成了01背包问题(即所有物品就只能使用1次)
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAXN 1000
#define MAXV 2000
int max(int i, int j)
{
return i>j?i:j;
}
int main()
{
int N=0,V=0,i=0,j=0;
scanf("%d %d",&N,&V);
if(!N||!V||N>MAXN||V>MAXV) return 1;
int v=0,w=0,s=0,pos=0;
int **newList = (int **)malloc(sizeof(int **));
memset(newList,0,sizeof(newList));
for(i=1;i<=N;i++)
{
scanf("%d %d %d",&v, &w, &s);
//二进制优化
int t=1;
//以 v=1,w=2,s=9 为例子,9=1+2+4 +2
//所以 s=2时 while结束 这9个物品就被分成4个,但是他们加起来的总价值和总体积不变
//分别是
//1,2
//2,4
//4,8
//2,4
while(s>t)
{
pos++;
newList = (int **)realloc(newList,sizeof(int **)*(pos+1)); //动态分配内存,防止空间浪费
newList[pos] = (int *)malloc(sizeof(int *)*2);
newList[pos][0]=v*t;
newList[pos][1]=w*t;
s-=t;
t*=2;
}
if(s>0)
{
pos++;
newList = (int **)realloc(newList,sizeof(int **)*(pos+1));
newList[pos] = (int *)malloc(sizeof(int *)*2);
newList[pos][0]=s*v;
newList[pos][1]=s*w;
}
}
int wList[V+1];
memset(wList,0,sizeof(wList));
//01背包问题的解法
for(i=1;i<=pos;i++)
{
for(j=V;j>=newList[i][0];j--)
{
wList[j]=max(wList[j],wList[j-newList[i][0]]+newList[i][1]);
}
}
printf("%d",wList[V]);
return 0;
}
节省空间的方法,一边读取数据,一边判断最优解;可以先理解上面的算法再来看下面的方法
#include "stdio.h"
#define MAXN 1000
#define MAXV 2000
#define max(x,y) x>y?x:y
int main()
{
int N=0,V=0,i=0,j=0;
scanf("%d %d",&N,&V);
if(!N||!V||N>MAXN||V>MAXV) return 1;
int v=0,w=0,s=0;
int dp[V+1];
memset(dp,0,sizeof(dp));
for(i=1;i<=N;i++)
{
scanf("%d %d %d",&v, &w, &s);
for(int k=1;k<=s;k*=2)
{
for(j=V;j>=k*v;j--)
{
dp[j]=max(dp[j],dp[j-v*k]+w*k);
}
s-=k;
}
if(s)
{
for(int j=V;j>=s*v;j--)
{
dp[j]=max(dp[j],dp[j-s*v]+s*w);
}
}
}
printf("%d",dp[V]);
return 0;
}