hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

        hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

        01背包的对物品的选择方案只有 0(不拿) 和 1(拿)吧, 完全背包对一件物品i的选择就有 k 种啦, k <= v / cost[i] (v为背包总量, cost[i]为i物品的花费) 

        多重背包, 拆分物品分成多件, 这里是用2的幂作为拆分因子的.

        假如当一件物品i的数量c和价值p的乘积c*p大于背包总量时, 可以认为物品i的数量无限啦, 所以就可以转化为完全背包咯. 否则就进行拆分, 把问题转为01背包. 

        拆分的目的就是为了转化问题为 01背包.

#include <stdio.h>
#include <string.h>

#define MAX 300

int dp[MAX], c[MAX], w[MAX], cnt[MAX];
int n, v;

inline int max(int a, int b) {
	return a > b ? a : b;
}

inline void zeroOnePack(int cost, int weight) {
	for (int j = v; j >= cost; j--) {
		dp[j] = max(dp[j], dp[j - cost] + weight);
	}
}

inline void completePack(int cost, int weight) {
	for (int j = cost; j <= v; j++) {
		dp[j] = max(dp[j], dp[j - cost] + weight);
	}
}

inline void multiplePack(int cost, int weight, int count) {
	if (cost*count >= v) {
		completePack(cost, weight);
		return ;
	}

	int k = 1;
	while (k <= count) {
		zeroOnePack(k*cost, k*weight);
		count -= k;
		k *= 2;
	} 

	if (cnt > 0) {
		zeroOnePack(count*cost, count*weight);
	}
}

int main() {
	int T;
	int i, j;

	while (scanf("%d", &T) != EOF) {
		while (T--) {
			memset(dp, 0, sizeof(dp));
			scanf("%d%d", &v, &n);
			for (i = 1; i <= n; i++) {
				scanf("%d%d%d", &c[i], &w[i], &cnt[i]);
			}

			for (i = 1; i <= n; i++) {
				multiplePack(c[i], w[i], cnt[i]);
			}

			printf("%d\n", dp[v]);
		}
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值