http://acm.hdu.edu.cn/showproblem.php?pid=2191
题意:你所拥有的金额为V,物品种类为n,每种价格为cost,重量为weight,数量有限为amount个,求用这些钱(可剩余)可以买到最多多重的粮食?
思路:每种物品数量有限,多重背包。直接用九讲里二进制优化过的模板就行。每种物品拆分为系数为2次幂的物品,对这些物品用以01背包的思想,背包不要求装满。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1005;
const int INF = 0x3f3f3f3f;
int dp[N], V;
void ZeroOnePack(int cost, int weight)
{
for(int j = V; j >= cost; j--)
dp[j] = max(dp[j], dp[j-cost]+weight);
}
void CompletePack(int cost, int weight)
{
for(int j = cost; j <= V; j++)
dp[j] = max(dp[j], dp[j-cost]+weight);
}
void MultiplePack(int cost, int weight, int amount)
{
if(cost*amount>=V)
{
CompletePack(cost, weight);
return;
}
int k = 1;
while(k < amount)
{
ZeroOnePack(cost*k, weight*k);
amount-=k;//注意在前面
k=k*2;
}
ZeroOnePack(amount*cost, amount*weight);
}
int main()
{
// freopen("in.txt", "r", stdin);
int t, n;
int cost[N], weight[N], amount[N];
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &V, &n);
for(int i = 1; i <= n; i++)
scanf("%d%d%d", &cost[i], &weight[i], &amount[i]);
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
MultiplePack(cost[i], weight[i], amount[i]);
/* for(int i = 0; i <= V; i++)
printf("%d ", dp[i]);
printf("\n");*/
printf("%d\n", dp[V]);
}
return 0;
}