1. 程式人生 > 其它 >AcWing 05多重揹包問題II

AcWing 05多重揹包問題II

題目連結 AcWing 5.多重揹包問題II

二進位制優化多重揹包


二進位制優化原理(不難證明)

對於一個整數S,不妨設 S = \((1101011)_{2}\) 為 7位2進位制整數,
我們可以由{\({2^0,2^1,2^2,2^3,2^4,2^5,2^6,2^7}\)}(集合中的元素要麼選,要麼不選)
組合成[0, S]內的任意一個整數

Case 1

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 12000;

int v[N], w[N];
int f[N];
int n, m, cnt;

int main()
{
    cin >> n >> m;
    
    for (int i = 0; i < n; i ++ )
    {
        int a, b, s;
        cin >> a >> b >> s;
        
        int k = 1;
        while(k < s)
        {
            cnt ++;
            v[cnt] = a * k;
            w[cnt] = b * k;
            s -= k;
            k *= 2;
        }
        
        if(s > 0)
        {
            cnt ++;
            v[cnt] = a * s;
            w[cnt] = b * s;
        }
        
    }
    
    n = cnt;
    
    for(int i = 1; i <= n; i ++)
        for(int j = m; j >= v[i]; j --)
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    
    cout << f[m] << endl;
    
    return 0;
}

Case 2

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 2010;

int n, m;
int f[N];

struct GOOD
{
    int v, w;
};

int main()
{
    cin >> n >> m;
    vector<GOOD> goods;
    for(int i = 0; i < n; i ++)
    {
        int a, b, s;
        cin >> a >> b >> s;
        
        int k = 1;
        while(k < s)
        {
            goods.push_back({k * a, k * b});
            s -= k, k *= 2;
        }
        if(s > 0) goods.push_back({s * a, s * b});
    }
    
    for(auto good : goods)
        for(int j = m; j >= good.v; j --)
            f[j] = max(f[j], f[j - good.v] + good.w);
    
    cout << f[m] << endl;
    
    return 0;
}