日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法设计与分析 0-1背包问题 动态规划解法【超详细】

發布時間:2024/2/28 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法设计与分析 0-1背包问题 动态规划解法【超详细】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

0-1背包問題 問題描述

給定i個物品和一個容量為的背包,物品的重量是Wi,其價值為Vi
物品個數為i,背包容量為C。
如何選擇裝入背包內的物品,使得裝入背包中的物品的總價值最大?

其中,每種物品只有全部裝入背包或不裝入背包兩種選擇。
物品不能分割,不能重復使用。

動態規劃算法思路

首先建立一個數組B[i][c],最上面一行表示背包容量,最左邊一列表示物品編號,中間填充的數值表示當當前背包容量為C,當前被考慮的物品編號為k的情況下,做出最優決定時產生的背包價值。

如下圖所示:(不用關心圖中數據,理解整體結構含義即可)

實例分析

已知背包的容量為20,并給定5種物品,其重量和價值如下圖所示:

令B(k,w)表示在前k個物品中能夠裝入容量為的背包中時,背包總價值的最大值。

得到如下動態函數:

利用上述函數,一行一行填表即可。
填表順序為:先從左上角開始,填第一行,第二行,…一直到結束,并不需要遞歸。
右下角即背包可裝下的最大價值26

詳細分析 疑難解答

可能有人會問,“當判斷一個物品k是否應該裝入背包的時候,難道不是只要能裝進去,就應該裝進去,這樣才是最優嗎”?

對于這個問題,我的理解是:

不一定非要裝進去當前能裝進去的物品。如果當前物品能裝進去,那么:

  • 放入第k件物品后,背包總價值 = 先給這件物品留出空間剩余的背包大小能裝進的最大價值 + 這件物品的價值
  • 不放入第k件物品,背包總價值 = 不用給這件物品留出空間當前背包大小能裝進的最大價值(就是判斷完上一件物品之后背包的價值)

說白了,就是當當前物品又大又輕時,雖然可以把它裝進去,但是在給它留出空間的同時,浪費了背包的容量。還不如不裝當前物品,而去選擇其他物品裝入。

那么這個“其他物品”指什么呢?就是在判斷這個物品該不該裝之前,已經計算過的當前背包容量下,可以將前k-1件物品放入或不放入時,背包的最大價值

如下圖,這是某一個物品“不放”比“放”好的例子:

用C代碼實現后,應該更容易理解一些(不懂的話請看注釋,重點在注釋):

//填表過程for (k = 1; k < N; k++){for (C = 1; C < W; C++){if (w[k] > C) //第k件物品放不進去 此時背包的價值 = 判斷完上一件物品之后背包的價值{B[k][C] = B[k - 1][C];}else{int value1 = B[k - 1][C - w[k]]+v[k]; //放入第k件物品后 背包總價值 = 先給這件物品留出空間,剩余的背包大小能裝進的最大價值 + 這件物品的價值int value2 = B[k - 1][C]; //不放入第k件物品 背包總價值 = 不用給這件物品留出空間,當前背包大小能裝進的最大價值(就是判斷完上一件物品之后背包的價值)if (value1 > value2){B[k][C] = value1;}else{B[k][C] = value2;}}}}

逆推裝入的物品

計算出矩陣以及最大可裝價值之后,如何逆推裝入的物品?
如下圖,從右下角開始,向上層層逆推。

  • 如果上下數字相同,說明這個物品未被放入背包。
  • 如果上下數字不同,說明這個物品已被放入背包,此時計算放入此物品之前背包剩余容量,并找出上一行對應位置。

附錄

我的筆記

運行結果
前幾行輸出為:某一個物品“不放”比“放”好的情況,可以無視
后面的矩陣才是最終的運算結果

完整代碼 C++

#include<iostream> #include<stdio.h> #define N 6 //物品的個數 #define W 21 //背包容量int B[N][W] = { 0 }; int w[6] = { 0,2,3,4,5,9 }; //物品重量 int v[6] = { 0,3,4,5,8,10 };//物品價值void knapsack() {int k; //第K個物品int C; //背包剩余重量//填表for (k = 1; k < N; k++){for (C = 1; C < W; C++){if (w[k] > C) //第k件物品放不進去 此時背包的價值 = 判斷完上一件物品之后背包的價值{B[k][C] = B[k - 1][C];}else{int value1 = B[k - 1][C - w[k]] + v[k]; //放入第k件物品后 背包總價值 = 先給這件物品留出空間,剩余的背包大小能裝進的最大價值 + 這件物品的價值int value2 = B[k - 1][C]; //不放入第k件物品 背包總價值 = 不用給這件物品留出空間,當前背包大小能裝進的最大價值(就是判斷完上一件物品之后背包的價值)if (value1 > value2){B[k][C] = value1;}else{B[k][C] = value2;if (value1 < value2)printf("k=%d C=%d\n", k, C);}}}} } int main() {knapsack();for (int i = 0; i < N; i++){for (int j = 0; j < W; j++){printf("%4d ", B[i][j]);}printf("\n\n");}system("pause"); }

總結

以上是生活随笔為你收集整理的算法设计与分析 0-1背包问题 动态规划解法【超详细】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。