動的プログラミング:0-1ナップザックの問題
動的プログラミングの一般的な手順:
- 問題構造分析
- 再帰的な関係の確立
- ボトムアップ計算
- 最良のソリューション追跡
例0-1ナップザックの問題
(件名:https://www.acwing.com/problem/content/description/2/)
タイトル説明
N個のアイテムと容量Vのバックパックがあります。各アイテムは1回のみ使用できます。
アイテムのボリュームは、私がVである私は、Wの値であり、I。
これらのアイテムの合計ボリュームがバックパックの容量を超えず、合計値が最大になるように、バックパックにパックするアイテムを見つけます。
最大値を出力します。
入力フォーマット
最初の行のスペースで区切られた2つの整数NとVは、それぞれアイテムの数とバックパックのボリュームを示します。
次に、N行があり、各行にはそれぞれスペースで区切られた2つの整数V i、W i、およびアイテムのi番目の値のボリュームがあります。
出力形式
最大値を表す整数を出力します。
データ範囲
0 <N、V≤10000
<vi、wi≤1000
入力例
4 5
1 2
2 4
3 4
4 5
サンプル出力
8
問題分析
特定のサイズのバックパックの場合、合計値の最大値を見つけます。各アイテムには2つの選択ケースのみがあり、選択されていない場合は、2つのケースの合計値を比較します。
f [i] [j]は、最初のiアイテムのみを見るという意味です。合計ボリュームがjの場合、最大合計値はいくつですか。
結果= max {f [n] [0〜V]}
f [i] [j]:
1.i番目の項目f [i] [j] = f [i-1] [j]を選択しないでください。2。i番目の項目f [i] [j]を
選択してください。= f [i-1] [jv [i];
f [i] [j] = max {1,2}の2つの場合で、最も大きく、最も大きいものを選択します。
初期化:f [0] [0] = 0;
コード1
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n,m; //n表示物体个数,m表示背包容量
int f[N][N];
int v[N], w[N] //v[N], w[N] 分别表示每个物品的体积和价值
int main(){
cin >> n >> m;
for(int i=0; i<n; i++){
cin >> v[i] >> w[i];
}
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++){
f[i][j] = f[i-1][j];
if(j >= v[i])
f[i][j] = max(f[i][j], f[i-1][j-v[i]] + w[i]);
}
int res = 0;
for(int i=0; i<=m; i++)
res = max(res,f[n][i]);
cout << res << endl;
return 0;
}
2次元アレイ状にf[N][N]
二次元配列の最適化に基づくf[N][N]
ために最適化されたf[N]
各外部ループ、F [m]は一回更新する。表現、jのi番目の値と記事の数の前にバックパックの最大容量は、前記;
コード2
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n,m; //n表示物体个数,m表示背包容量
int f[N]; //表示背包体积为j时前i个物品的最大价值为多少
int v[N], w[N] //v[N], w[N] 分别表示每个物品的体积和价值
int main(){
cin >> n >> m;
for(int i=0; i<n; i++){
cin >> v[i] >> w[i];
}
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]); //f[j]滚动记录最优解
}
cout << f[m] << endl;
return 0;
}