この記事には、シリーズのナップザック問題について説明します。
[1] 01-バックパックとその応用
[2]完全にバックパックとその応用
[3]複数のバックパック
[1] 01-バックパックとその応用:
1.1,01-ナップザック問題の説明:
Nアイテムやバックパックの容量Cがあります。W [i]は、値V [i]があると、i番目の商品の重量。これらの項目の重みの和がバックパックの容量、および最大値の合計を超えないことができ、バックパックの中に物品を解きます。以下のような:
私のアイテム | 重ワット | 値v |
---|---|---|
1 | 2 | 3 |
2 | 3 | 4 |
3 | 4 | 5 |
4 | 5 | 6 |
ここで、N = 4、C = 8、10の最大値(すなわち、アイテムバックパックに2及び4)。
1.2,01-ナップザック問題解決のアイデア:
01-、ナップザック問題動的プログラミングを解決するのに適したDPを有する[I] [j]はバックパックの最大値jの容量にアイテム前にi番目を表すので、この問題は、問題の充填となります。上記の例のように、DP [4] [8]最終的な答えです。
キーは、状態遷移方程式を見つけることです。今2例、次に、[I] [J] DPを計算すると仮定します。
- jは商品の重量の電流容量よりも小さい場合、I(J <W [i])と 、 次いで、i番目の商品を確実にしないバックパックに、バックパックまたは単にこのI-1番目の項目の前に、すなわち
dp[i][j] = dp[i-1][j]
。 - jが現在の容量よりも大きい場合に商品の重量に等しいI(J≥W [i])と 、 その後、バックパックに基本条件のi番目のアイテム。だから、最終的には最初の場所に追加することはできません最大の合計値のかどうか、私の項目に依存します。合計値を最大化していない場合、それはまだ
dp[i][j] = dp[i-1][j]
、私は最初の項目にはない表し、あなたが全体の価値を最大化できるかどうか、そしてdp[i][j] = dp[i-1][j-w[i]] + v[i]
、どこdp[i-1][j-w[i]]
i番目の項目は、充電された状態の前にあります。
1.3,01-バックパックのpython3を達成します:
class Solution:
def knapsack01(self, N, w, v, C):
'''
@param N: int, 物品总数
@param w: List, 物品重量
@param v: List, 物品价值
@param C: int, 背包容量
'''
dp = [[0] * (C+1) for _ in range(N+1)]
for i in range(1, N + 1):
for j in range(1, C+1):
if j < w[i-1]:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]] + v[i-1])
return dp[-1][-1]
N = 4
w = [2,3,4,5]
v = [3,4,5,6]
C = 8
print(Solution().knapsack01(N, w, v, C)) # 10
さらに次の行の更新は[I wは<Jより確かに小さいのでJ <[I] [j]はDP [I-1] [j]を= DPを更新するには、[I-1]、wは、実際には役に立たない場合、ことを見出しました-1]ここで場合。したがって、中間コードを簡略化することができます。
for i in range(1, N + 1):
for j in range(w[i-1], C+1):
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]] + v[i-1])
1.5,01-袋スペースの最適化:
{1 ... J X}に関連する、DP [I-1] [X]は、最後のサイクルなおさらなるたびDPは[I] [j]は[I-1] [X]をDPのみ変更されることを見出しました保存された値;
従って、DPは、空間を最適化する目的を達成するために、1次元配列に圧縮することができる、状態遷移方程式はに変換されますdp[j] = max(dp[j], dp[j-w[i]] + v[i])
。
注:状態遷移方程式、Vによってそれぞれ誘導されるV(I)(J)(I-1)(JW (i))を一次元アレイはJの降順にスキャンするように、誘導される(容量)を0に、1サイクル前にエラーが発生し、これらの値が変更されるかどうかを保存します。
次のように中間コードが簡略化されます。
for i in range(1, N+1):
for j in range(C, w[i-1]-1, -1):
dp[j] = max(dp[j], dp[j-w[i-1]] + v[i-1])
01-バックパックLeetcodeのトピックに関連した1.4:
416:アレイは、2つの等しいサブセットに分割することができるかどうかを決定し
[2]完全にバックパックとその応用
2.1、完全なナップザック問題の説明:
各項目は、無限要素が利用可能である有し、そこに商品のN種類であり、バックパックの容量はCです。wiのi番目の記事の重量は、値がviのです。これはバッグにアイテムを解決する、これらの項目の総容積はバックパックの容量、及び最大の合計値を超えることはできません。最大出力値。
入力フォーマット:
スペースで区切られた2つの整数、N、C、の最初の行は、それぞれ、商品の種類やバックパックの体積を表します。
次いで、N行、各行二つの整数部WI、VI、それぞれ、スペースで区切られた、物品のi番目の値の重みがあります。
出力フォーマット:
出力最大値を表す整数。
データ範囲:
- 0 <N、C≤1000年
- 0 <WI、我々は1000年≤します
サンプル入力:
4 5
1 2
2 4
3 4
4 5
出力例:
10
2.2、フルバックパック問題解決のアイデア:
違いは、01-リュック完全ナップザック問題に各アイテムが無限数を有することを意味するということです。
2.3、C ++の実装:
ます。https://www.jianshu.com/p/7b60dfc8d1bdで再現