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

来源:互联网 发布:死神辣条淘宝 编辑:程序博客网 时间:2024/06/05 07:20

        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 300int 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;}