0-1揹包問題(動態規劃)
#include <iostream>
#include <cstring>
using namespace std;
const int N=15;
int main()
{
int v[N]={0,8,10,6,3,7,2};
int w[N]={0,4,6,2,2,5,1};
int m[N][N];
int n=6,c=12;
memset(m,0,sizeof(m));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=c;j++)
{
if(j>=w[i])
m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]);
else
m[i][j]=m[i-1][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=c;j++)
{
cout<<m[i][j]<<' ';
}
cout<<endl;
}
return 0;
}
問題描述:0-1揹包問題,給定n種物品,和一個容量為C的揹包,物品 i 的重量是W[ i ] ,價值為V[ i ] ,問:應該如何選擇裝入揹包的物品,使得裝入揹包中物品的價值最大?
要求,對於每一個物品,我們只能選擇拿與不拿,並不能裝入物品的一部分,也不能裝入多個同樣的物品。
解題思路:在給定空間C的情況下選擇 n 個物品中的某些物品,對於每一個物品只有拿與不拿。可以想象在選擇第i個物品時可以拿,也可以不拿,如果拿了第i個物品,這時候的價值可以等價於 用C-w[i]的空間選擇i-1個物品的價值 + v[ i ] 。 如果不拿,這時候的價值相當於利用C的空間選擇i-1個物品的價值(注意,不拿的情況下空間大,最優解不一定小於拿的情況。)。因此,對於第i個物品的選擇由前邊的兩種情況的最大值決定。(這中解題思路是一種逆向思維,是從後邊往前走的。而在計算時是由前往後計算的)
建立模型:宣告一個大小為m[ n ][ c ]的二維陣列,m[i][j]表示,在面對第i件物品的選擇時,利用j的空間選擇前i件物品能得到的最大值。根據上邊的分析很容易得到m[i][j]的計算方法。
(1)如果j < w [ i ] ,這時候揹包容量不足以放下第 i 件物品,只能選擇不拿,這時候對於m[i][j]的選擇只能有 m[ i - 1 ][ j ](在j空間中對前i-1個物品進行最優選擇)所決定。
m[ i ][ j ] = m[ i-1 ][ j ]
(2)如果j<w[i],這時候揹包容量可以放下第i件物品,我們就要考慮放下這個物品能否創造最大價值,即第i件物品是否在最優解中,因此這時候我們就要比較
m[ i - 1 ][ j ] 和 m[ i-1 ][ c - w[ i ] ] (在c - w[ i ] 的空間中面對i - 1 個物品進行最優選擇,這裡的m[ i-1 ][ j-w[ i ] ]指的就是考慮了i-1件物品,揹包容量為j-w[i]時的最大價 值,也是相當於為第i件物品騰出了w[i]的空間。)大小來判斷 i 是否選擇,(而在實際計算中我們對於這兩項並不瞭解,因此需要從前往後計算)。
狀態轉移方程:
if(j>=w[i])
m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]);
else
m[i][j]=m[i-1][j];
例:0-1揹包問題:(來源:https://blog.csdn.net/xp731574722/article/details/70766804)
在使用動態規劃演算法求解0-1揹包問題時,使用二維陣列m[ i ][ j ]儲存 j 空間下面對 i 件物品的最優解 ,而使用動態規劃演算法求解時其實就是對二維陣列m[ i ][ j ]的繪製過程。
價值陣列 V[ n ] = {8, 10, 6, 3, 7, 2}
重量陣列 M[ n ] = {4, 6, 2, 2, 5, 1} 揹包容量為C = 12
(第一行和第一列為序號,其數值為0)
如m[2][6],在面對第二件物品,揹包容量為6時我們可以選擇不拿,那麼獲得價值僅為第一件物品的價值8,如果拿,就要把第一件物品拿出來,放第二件物品,價值10,那我們當然是選擇拿。m[2][6]=m[1][0]+10=0+10=10;依次類推,得到m[6][12]就是考慮所有物品,揹包容量為C時的最大價值。
程式碼實現:
#include <iostream>
#include <cstring>
using namespace std;
const int N=15;
int main()
{
int v[N]={0,8,10,6,3,7,2};
int w[N]={0,4,6,2,2,5,1};
int m[N][N];
int n=6,c=12;
memset(m,0,sizeof(m));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=c;j++)
{
if(j>=w[i])
m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]);
else
m[i][j]=m[i-1][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=c;j++)
{
cout<<m[i][j]<<' ';
}
cout<<endl;
}
return 0;
}
到這一步,可以確定的是可能獲得的最大價值,但是我們並不清楚具體選擇哪幾樣物品能獲得最大價值。
另起一個 x[ ] 陣列,x[i]=0表示不拿,x[i]=1表示拿。
m[n][c]為最優值,如果m[n][c]=m[n-1][c] ,說明有沒有第n件物品都一樣,則x[n]=0 ; 否則 x[n]=1。當x[n]=0時,由x[n-1][c]繼續構造最優解;當x[n]=1時,則由x[n-1][c-w[i]]繼續構造最優解。以此類推,可構造出所有的最優解。
void traceback()
{
for(int i=n;i>1;i--)
{
if(m[i][c]==m[i-1][c])
x[i]=0;
else
{
x[i]=1;
c-=w[i];
}
}
x[1]=(m[1][c]>0)?1:0;
}
參考(https://blog.csdn.net/xp731574722/article/details/70766804)
相關文章
- 動態規劃解0-1揹包問題動態規劃
- 動態規劃之 0-1 揹包問題詳解動態規劃
- 【動態規劃】0-1揹包問題原理和實現動態規劃
- 【動態規劃】揹包問題動態規劃
- 揹包問題----動態規劃動態規劃
- 動態規劃 01揹包問題動態規劃
- 【動態規劃】01揹包問題動態規劃
- 動態規劃--01揹包問題動態規劃
- 動態規劃篇——揹包問題動態規劃
- 動態規劃-01揹包問題動態規劃
- 【動態規劃】01揹包問題【續】動態規劃
- 動態規劃之0,1揹包問題動態規劃
- 動態規劃系列之六01揹包問題動態規劃
- 動態規劃-揹包01問題推理與實踐動態規劃
- 01揹包問題理解動態規劃演算法動態規劃演算法
- 詳解動態規劃01揹包問題--JavaScript實現動態規劃JavaScript
- 詳解動態規劃01揹包問題–JavaScript實現動態規劃JavaScript
- 【動態規劃】一次搞定三種揹包問題動態規劃
- python 動態規劃(揹包問題和最長公共子串)Python動態規劃
- leetcode題解(0-1揹包問題)LeetCode
- 整數0-1揹包問題
- 演算法-動態規劃-完全揹包演算法動態規劃
- 【演算法】0-1揹包問題演算法
- 01揹包動態規劃空間優化動態規劃優化
- 多重揹包動態規劃及空間優化動態規劃優化
- 前端與演算法-動態規劃之01揹包問題淺析與實現前端演算法動態規劃
- 【LeetCode動態規劃#08】完全揹包問題實戰與分析(零錢兌換II)LeetCode動態規劃
- 揹包問題演算法全解析:動態規劃和貪心演算法詳解演算法動態規劃
- 【LeetCode動態規劃#06】分割等和子集(01揹包問題一維寫法實戰)LeetCode動態規劃
- 【LeetCode動態規劃#10】完全揹包問題實戰,其三(單詞拆分,涉及集合處理字串)LeetCode動態規劃字串
- 揹包問題(01揹包與完全揹包)
- 動態規劃之子序列問題動態規劃
- 前端學習演算法2: 揹包問題 ,一步一步思考(動態規劃入門)前端演算法動態規劃
- 揹包問題
- 找零問題與動態規劃動態規劃
- 醜數問題——動態規劃、Java動態規劃Java
- 動態規劃之股票問題123動態規劃
- 動態規劃,股票問題留坑動態規劃