バックパックに関する9つの講義(2)-完全なバックパックの問題
ここからダウンロードできる有名なバックパッキングに関する9つのレクチャー、前の記事の01バックパックの問題を参照してください。
1.1問題
バックパックにはN
さまざまな種類の商品と容量がありV
、各アイテムには無制限のメンバーがあり、最初のi
コストのアイテムにはC iC_iがありますC私、得られる値はW iW_iです。W私。全体的な価値を最大化するためにバックパックにパックするアイテムを見つけます。
1.2問題解決のアイデア
完全なバックパックと01バックパックの唯一の違いは、アイテムを複数回選択できるかどうかです。
この違いを知っていると、実際、慎重に考えると、単一のアイテムC i C_iについて、容量Vが制限されているため、バックパックの問題を01バックパックに完全に変換できます。C私言い換えれば、⌊V/Ci⌋\ left \ lfloor V / C_i \ right \ rfloorのようにしか置くことができません⌊ V / C私⌋個なので、完全なバックパックの問題を⌊V/C1⌋\ left \ lfloor V / C_1 \ right \ rfloorと見なすだけで済みます。⌊ V / C1⌋アイテムC1 C_1C1、有⌊V/C2⌋\ left \ lfloor V / C_2 \ right \ rfloor⌊ V / C2⌋アイテムC2 C_2C2、…、⌊V/CN⌋\ left \ lfloor V / C_N \ right \ rfloor⌊ V / CN⌋アイテムCN C_NCN01バックパックの問題で十分です。ただし、この時点での全体的な複雑さは、O(NV ∑ VC i)O(NV \ sum \ cfrac {V} {C_i})と見なすことができます。O (N V∑C私V)、この複雑さは少し高いです〜
さらに、実際にはより効率的な変換方法があります。バイナリ思考を使用して、i番目のアイテムをC i 2 K C_i2 ^ Kのコストに分解できます。C私2K、値はW i 2 k W_i2 ^ kです。W私2k個のアイテム。ここでkは1からCi2k≤VC_i2^C私2k≤Vの最大整数(実際、kはすべてのiアイテムのコストを取り、V未満の整数を取ることができます)、次に時間の複雑さをO(NV log(⌊V/C2⌋))O(NVlog(\ left \ lfloor V / C_2 \ right \ rfloor))O (N VのL O G (⌊ V / C2⌋))もう一度。以前よりずっと低い〜
もちろん、ほとんどのnbソリューションは上記のhhhではありません。01ナップザックの問題を解決するには、vvが必要です。v V、V − 1、..、0 V、V-1、..、0から降順V 、V−1 、。。、0 dp [v] dp [v]を計算しますd p [ v ]、 vのデクリメント計算は、状態dp [v] dp [v]を保証することです。d p [ v ]は前のラウンドから再帰的に導出されます。実際には、アイテムが1回だけ選択されるようにするためですが、現在は複数回選択できます。それは美しいではありませんか?非常に簡単です。vをインクリメントしてdp [vを計算します。 ]はい、次の疑似コードを参照してください。
dp[0...V] ← 0
for i ← 1 to N // 依次遍历N件物品
for v ← Ci to V // 能装下当前物品的背包使用状态方程
dp[v] ← max{
dp[v], dp[v-Ci]+Wi}
したがって、現時点では、問題の複雑さはO(NV)O(NV)に減少しています。O (N V )、秒〜
しかし、01バックパックの絶え間ない最適化は完全なバックパックには存在しません〜
2つの項目i、jがC i <C j C_i \ lt C_jを満たす場合、単純で効果的な最適化C私<CJ連結Wi≥WjW_i\ ge W_jW私≥WJ、次に、アイテムjを直接削除できます。このプロセスは、O(N 2)O(N ^ 2)で行うことができます。O (N2)時間の複雑さはそれほど高くありません。時間に追われている場合は、この単純な最適化を試すことができます〜
1.3サンプルコード
私は書くのが面倒です〜01バックパック問題コードと同様に、独自のデータを作成する必要があります
1.4実際の戦闘段階
いくつか質問をしてください、そしてそれは明らかになるでしょう!!
タイトルの説明:
Li Yuxiangは才能のある子供であり、彼の夢は世界で最も偉大な医師になることです。このため、彼は近くで最も権威のある医師を教師として崇拝したかったのです。彼の適性を判断するために、医者は彼に難しい問題を提示した。医者は彼をハーブでいっぱいの洞窟に連れて行き、彼に言った:「私の子供、この洞窟にはいくつかの異なる種類のハーブがあります。それぞれを選ぶのに時間がかかり、それぞれに独自の価値があります。私はいくつかのハーブを集めることができる期間を与えてください。あなたが賢い子供であるならば、あなたはあなたが集めるハーブの総価値を最大にすることができるはずです。」
LiYuxiangの場合、このタスクを完了できますか?
この質問と元の質問の違い:
-
各ハーブは制限なしに乱暴に選ぶことができます。
-
薬の種類が眩しくて、薬を集める時間がとても長いです!マスターは菊が感謝するのを待っていました!
特定の入力および出力形式とサンプルについては、元の質問のWebサイトを参照してください〜
これは典型的な完全なナップザックの問題です。上記のアイデアに従って直接書き込むことができますが、この質問のデータ量は比較的多いです。dp配列のlong long
タイプに注意し、メモリの爆発を防ぐために配列を動的に生成します。STLもあります。mallocをゆっくり使う
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main() {
ios::sync_with_stdio(false), cin.tie(NULL);
// 静态数组会爆内存
//int V[N] = { 0 }, C[N] = { 0 }, t, m;
//long long dp[N] = { 0 };
int t, m;
cin >> t >> m;
int* V = (int*)malloc(m * sizeof(int));
int* C = (int*)malloc(m * sizeof(int));
long long* dp = (long long*)malloc((t+1) * sizeof(long long));
// STL太慢了
//vector<int> V(m);
//vector<int> C(m);
//vector<long long> dp(t+1);
for (int i = 0; i < m; i++) {
cin >> C[i] >> V[i];
}
for (int i = 0; i < m; i++) {
for (int j = C[i]; j <= t; j++) {
dp[j] = max(dp[j], dp[j - C[i]] + V[i]);
}
}
cout << dp[t] << endl;
free(V);
free(C);
free(dp);
return 0;
}
結果の送信:
STLを使用する場合。。。。
STLはmallocの2倍です〜もちろん、ここで時間が止まらなければ効果はありません