複数のナップサック問題2 |バイナリ分割

複数のナップサック問題2


5を取得してから
制限時間:1秒
スペース制限:64MB

タイトル説明:

N個のアイテムとVの容量を持つバックパックがあります。

i番目のアイテムには最大でsi個のアイテムがあり、各アイテムのボリュームはviで、値はwiです。

アイテムの総量がバックパックの容量を超えないように、どのアイテムがバックパックにロードされているかを解決し、合計値が最大になります。
最大値を出力します。

入力フォーマット:

最初の行の2つの整数NとVはスペースで区切られ、それぞれオブジェクトの数とバックパックのボリュームを示します。

次に、N行があり、それぞれに3つの整数vi、wi、siがあり、スペースで区切られ、i番目のアイテムの量、値、および数量を示します。

出力フォーマット:

最大値を表す整数を出力します。

データ範囲:

0 <N <= 1000

0 <V <= 2000

0 <vi、wi、si <= 2000

入力サンプル:

4 5
1 2 3
2 4 1
3 4 3
4 5 2

サンプル出力:

10

複数ナップサック問題2は、複数ナップサック問題1に基づいており、データ量が非常に多くなり、以前のアルゴリズムは機能しません。

この問題の解決策の多くは、特定のアイテムのバイナリ分割です。

 	int v,w,s;cin>>v>>w>>s;
    for(int j = 1;j <= s;s -= j,j *= 2)

コードからわかるように、アイテムは1、2、4、8 ...の複数の部分に分割され、各部分は新しい商品と見なされます。

次に、01バックパックと同様の操作を実行します。

なぜこれができるのですか?

たとえば、ある製品に7つのアイテムがあり、それを3つの新しいパーツ1、2、4に分割します。パーツごとに01バックパック操作を実行し、各パーツには、次に、これらの3つを介して2つの部分をすべての状況に組み合わせることができます(1、2、および4の選択に応じて、0から7までの合計8つの状況に組み合わせることができます)。したがって、3つの部分に分けられますが、製品のピースの数のすべての状況が必要ですそれらはすべて一緒に来ることができます。

次に、バイナリ分割後、時間計算量はO(logn)になります。特定の製品は1024個ありましたが、10個に分割するだけで、はるかに効率的です。

コード:
#include<iostream>
using namespace std;
int N,V,dp[2005];       //dp表示背包状态
int main(){
    
    
    cin>>N>>V;
    for(int i = 1;i <= N;++i){
    
    
        int v,w,s;cin>>v>>w>>s;
        for(int j = 1;j <= s;s -= j,j *= 2){
    
           //二进制拆分
            for(int k = V;k >= j * v;--k)
                if(dp[k] < dp[k - j * v] + j * w)
                    dp[k] = dp[k - j * v] + j * w;
        }
        if(s)                             //二进制拆分剩余
            for(int k = V;k >= s * v;--k)
                if(dp[k] < dp[k - s * v] + s * w)
                    dp[k] = dp[k - s * v] + s * w;
    }
    cout<<dp[V];
    return 0;
}

おすすめ

転載: blog.csdn.net/qq_45985728/article/details/113619804