[多重背包] POJ1276 Cash Machine (二进制优化)

题目

有各种不同面值的货币,每种面值的货币有不同的数量,请找出利用这些货币可以凑成的最接近且小于等于给定的数字cash的金额。

思路

多重背包模板题。
1.朴素的多重背包,每个状态转移时枚举用的某种货币的个数,复杂度: O ( C n [ i ] ) ,TLE。
2.二进制优化,背包九讲里面有。
此处应该注意的是,1…n的任意整数用尽量少的几个整数表示成和的形式的最优解问题。

代码

朴素的多重背包

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;

const int maxn = 10 + 5;
const int maxm = 100000 + 100;
int c, n, k[maxn], w[maxn], d[maxm];

int main() {
    while (scanf("%d%d", &c, &n) == 2) {
        _rep(i, 1, n) scanf("%d%d", &k[i], &w[i]);
        memset(d, 0, sizeof(d));
        _rep(i, 1, n)
            for (int j = c; j >= w[i]; j--)
                _rep(kk, 1, k[i])
                    if (j >= kk * w[i])
                        d[j] = max(d[j], d[j - kk * w[i]] + kk * w[i]);

        int ans = 0;
        _rep(i, 1, c) ans = max(ans, d[i]);
        printf("%d\n", ans);
    }

    return 0;
}

二进制优化
这里写图片描述

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;

const int maxn = 10 + 5;
const int maxm = 100000 + 100;
int c, n, k[maxn], w[maxn], d[maxm];

int main() {
    while (scanf("%d%d", &c, &n) == 2) {
        _rep(i, 1, n) scanf("%d%d", &k[i], &w[i]);
        memset(d, 0, sizeof(d));

        _rep(i, 1, n) {
            if (k[i] * w[i] >= c) {  // 完全背包过程
                _rep(j, w[i], c)
                    d[j] = max(d[j], d[j - w[i]] + w[i]);
            }
            else {  // 二进制分物体后的01背包问题
                int l = 1, amount = k[i];
                while (l < amount) {
                    for (int j = c; j >= w[i] * l; j--)
                        d[j] = max(d[j], d[j - w[i] * l] + w[i] * l);
                    amount -= l;
                    l *= 2;
                }
                for (int j = c; j >= w[i] * amount; j--)
                    d[j] = max(d[j], d[j - w[i] * amount] + w[i] * amount);
            }
        }

        int ans = 0;
        _rep(i, 1, c) ans = max(ans, d[i]);
        printf("%d\n", ans);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/81116606