動的計画法でナップザック0-1の問題を解決する方法は知っていますが、O(N * C)(Nアイテム、C容量)の複雑さを損なうことなく、どのアイテムを取るかを判断するのに苦労しています。
何かアイデアはありますか(ボトムアップアプローチをお勧めします)?
動的計画法でナップザック0-1の問題を解決する方法は知っていますが、O(N * C)(Nアイテム、C容量)の複雑さを損なうことなく、どのアイテムを取るかを判断するのに苦労しています。
何かアイデアはありますか(ボトムアップアプローチをお勧めします)?
今、結果を配列bool[] a
に格納していると仮定します。ここa[i]
で、合計i
が達成できる場合はtrueです。
別の配列が必要になります。int[] b
ここで、b[i]
は合計を達成するためにナップザックに配置した最後の要素ですi
。
だから、あなたが持っていた場所
a[i] = true;
あなたは必要になるでしょう
a[i] = true;
b[i] = current_item;
次に、合計を達成するためにどの項目を取ることができるかを見つけることi
は単純なループです。
PS簡単にするために2つのアレイを使用していますが、明らかにアレイa
は削除できます。
O(n)回でパスを再構築するための変更は次のとおりです
int knapsack(int weight[], int profit[], int no_of_items, int capacity) {
for (int var = 0; var <= capacity; ++var) {
dp[0][var] = 0;
}
for (int var = 0; var <= no_of_items; ++var) {
path[var] = false;
}
int using_item_i, without_using_item_i;
for (int i = 1; i <= no_of_items; ++i) {
for (int j = 1; j <= capacity; ++j) {
without_using_item_i = dp[i - 1][j];
using_item_i = 0;
if ((weight[i]) <= j) {
using_item_i = dp[i - 1][j - weight[i]] + profit[i];
}
if (using_item_i >= without_using_item_i) {
taken[i][j] = true;
dp[i][j] = using_item_i;
} else {
taken[i][j] = false;
dp[i][j] = without_using_item_i;
}
}
}
//Reconstructing back the path
int j = capacity;
for (int i = no_of_items; i >= 0; --i) {
if (taken[i][j]) {
path[i] = true;
cnt++;
}
j = j - weight[i];
}
return dp[no_of_items][capacity];
}
boolean[] solution = new boolean[nItems];
for (int i = nItems, c = maxCapacity; i > 0 && c > 0; i--) {
int iThItemAddedValue = value[i - 1][c - weights[i - 1]] + values[i - 1];
int iThItemInheritedValue = value[i - 1][c];
if (iThItemAddedValue > iThItemInheritedValue) {
solution[i - 1] = true;
c = c - weights[i - 1];
} else {
solution[i - 1] = false;
}
}
https://www.dropbox.com/s/ish7t5vgy91fovt/Screenshot%202017-01-01%2015.16.31.png?dl=0
呼び出し元で tmpList を出力すると、答えが得られます