acwing 5.複数のナップサック問題II(バイナリ最適化)

トピック

ここに画像の説明を挿入します

回答

複数のバックパックの最適化:複数のバックパックのプレーンバージョンはO(nms)であり、この質問のデータ範囲は間違いなくタイムアウトになります

それは、最適化することができない
ここに画像の説明を挿入します
ことで、完全なナップザックの方法式をリストすることによって、最後に余分な項目があることが見つかりませんし、完全なナップザックの数が無限大であるので、これ以上があるでしょうザ・。 f [i] [jv]の最大値は次のとおりです。f[i] [j]を更新できませんでした

バイナリ最適化:たとえば、i番目のアイテムを選択する場合、アイテムの数が30であるとします。バックパックの容量を超えていない場合は、0、1、2…30を選択して、状態方程式を更新できます。時間計算量あるO(S)。マジックはここにある。私たちは、一緒に2これらの30個の数字を入れて、バイナリを使用することができます0、2 1、2 2、2 3を、そして最後に15(2あり4彼らは合計を超えます= 16 30なので、最後に15を追加します)、つまり1、2、4、8、15(i番目のアイテムが非常に多くの部分に分割されてパッケージ化されている場合は、対応するボリュームと値にも対応するボリュームと値を掛ける必要があります値)、13 = 1 + 4 + 8などの0〜30の数値を考え出すことができるので、毎回この新しいグループを選択するかどうかを検討するだけで済みます。はい、これは完全に01ナップザックに変換されます。問題、時間複雑さはO(logs)になります

コード

#include<bits/stdc++.h>

using namespace std;
const int N = 25000;

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

int main() {
    
    

    cin >> n >> m;

    for (int i = 1; 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;

    //转化为01背包问题
    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;
}

おすすめ

転載: blog.csdn.net/qq_44791484/article/details/114655854