01ナップザック問題
件名の説明:
N項目Vとバックパックの容量があります。各項目は、一度だけ使用することができます。アイテムのボリュームはI〜V、値のwiです。
これはバッグにアイテムを解決する、これらの項目の総容積はバックパックの容量、及び最大の合計値を超えることはできません。
最大出力値。
入力フォーマット:
二つの整数N、Vの最初の行はそれぞれ、スペースで区切られた、及び物品の数は、ボリュームのバックパック。次いで、N行、二つの整数viは、wiはそれぞれスペースで区切られた各列、及びアイテムのi番目の値の量が存在します。
分析:
一つだけ、各項目の、あなたは入れてホールドするように選択することができます。状態遷移方程式を得るために、動的プログラミングを使用するのは簡単ですので。
f[i][j]=max{f[i-1][j],f[i-1][j-v[i]]+w[i]} // f[i][j]表示前i件物品恰放入一个容量为j的背包可以获得的最大价值。
状態遷移方程式を用いて、我々は、直接01ナップザック問題の二次元配列の溶液を書き込むことができます。
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main()
{
cin>>n>>m;
for(int i = 1;i<=n;i++){
cin>>v[i]>>w[i];
}
for(int i =1;i<=n;i++){
for(int j = 0;j<=m;j++){
f[i][j] = f[i-1][j];//不含第i个物品
if(j>=v[i]) f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
}
cout<<f[n][m]<<endl;
return 0;
}
時間とプロセスの空間計算量はO(nm)です。、時間計算量が最適化されていない、我々は状態遷移方程式、F [i]は[]およびF [I-1] []のみ関連することを観察することができるO(N)に空間的複雑度を最適化し続けることができます。その後、我々は一次元配列F [0 ... V] Fを表すために使用することができる[I] [0 ... V]、状態遷移方程式は、次のとおり
f[j] = max(f[ j ],f[ j-v[i] ]+w[i]);
一次元転送方程式maxの(F [J]、F [JV [I] + [I] W) と二次元状態遷移方程式最大{F [I-1]〜 [J]、F [I-1 ] [JV [I] + W [I]} 我々は順次列挙ではなく、M降順列挙を必要とするバックパックのサイズに対応します。なぜ?なぜ逆列挙は、あなたがこの記事を見ることができhttps://blog.csdn.net/xiajiawei0206/article/details/19933781
または独自のデータは、それがある方法で、順次列挙を押して何をシミュレート理解しやすいです。
以下01バックパック一次元アレイ最適化されたコードです。
// 一维数组优化版
#include<iostream>
#include<algorithm>
using namespace std;
const int N =1010;
int n,m;
int v[N],w[N];
int f[N];
int main(){
cin>>n>>m;
for(int i=1;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]);
}
}
cout<<f[m]<<endl;
return 0;
}
私たちは、直接01ナップザック問題のテンプレートを取得することができます
//m为背包大小.cost为代价,weight为价值
void ZeroOnePack(int cost,int weight)
{
for(int i=m;i>=cost;i--)
f[i] = max(f[i],f[i-cost]+weight);
}
ナップザック問題は、問題の変異体の数を聞かれることがあり、一部はちょうど満たされたバックパックを必要とし、いくつかは聞いてませんでした。どちらも初期設定が異なっています。あなただけのバックパックを埋めるために必要がある場合は、Fを除いて、初期化[0] 0他のF [1 ... V]が-∞に設定されている、ちょうど埋めを必要とせず、F [0 ... V]がすべて設定されている場合、それが初期化されるべき0。