/*
多重背包:介于0-1背包和完全背包之间。容积为V的背包,给定一些物品,每种物品包含体积w,价值v和数量k,求用该背包能装下的最大价值总量。
每种武平可选的数量不再为无穷或者1,而是一个确定的数k。将多重转换为0-1背包。即每种物品被视为k种不同物品,对所有物品求0-1背包。
将原数量为k的物品拆分为若干组,每组物品包含的原物品个数分别为:1,2,4,...,k-2的c+1次方,其中c为使k-2的c+1次方>0的最大整数。类似与
二进制拆分。可以得到0到k之间任意物品价值重量和。对所有这些信物品做0-1背包。
问题:支援灾区。你有n元,市场有m种大米,每种打磨都是袋装产品,价格不等,并且只能整袋购买。你最多能采购多少公斤粮食
输入:第一行1个正整数C(表示有C组测试用例),每组测试用例的第一行时两个整数n和m(1<=n<=100,1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据。
每行包括3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
输出:输出能够购买大米最多重量,经费可以不用完
输入:
1
8 2
2 100 4
4 100 2
输出:
400
关键:
1多重背包转化为0-1背包后,采用逆序
2 背包问题:外层循环是物体,内层循环是总容积,对每个物品求其价值总和
3 拆分方法:
while(k-c>0)
{
k -= c ;
list[++iCnt].v = v*c;
list[iCnt].w = w*c;
c *= 2
}
//注意最后一次拆分是用k乘不是用c乘
list[++iCnt].v = k*v;
list[iCnt].w = k*w;
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int max(int a,int b)
{
return a>b ? a:b;
}
typedef struct List
{
int w;//体积
int v;//价格
}List;
int main(int argc,char* argv[])
{
int T;
int s,n;
int i,j;
int w,v,k;
while(scanf("%d",&T))
{
while(T--)
{
List list[2001];
int dp[101];//总共最多100元,相当于容积
scanf("%d %d",&s,&n);
int iCnt = 0;//用于计数拆分后的物品总数
for(i = 0 ; i < n ; i++)
{
scanf("%d %d %d",&w,&v,&k);
//开始进行多重背包的拆分
int c = 1;
while(k - c > 0)
{
k -= c;//拆分
list[++iCnt].v = c*v;
list[iCnt].w = c*w;
c *= 2;
}
//易错,最后一次的k小于c,也要拆分,这里是乘以k倍而不是c倍
list[++iCnt].v = k*v;
list[iCnt].w = k*w;
}
//背包初始化,s为总体积
for(i = 0 ; i <= s; i++)
{
dp[i] = 0;
}
//背包计算,cnt为物品数,s为总体积
for(i = 1 ; i <= iCnt ; i++)
{
for(j = s; j >= list[i].w ; j--)
{
dp[j] = max(dp[j],dp[j-list[i].w] + list[i].v);
}
}
printf("%d\n",dp[s]);
}
}
system("pause");
getchar();
return 0;
}