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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

一文读懂背包问题

發布時間:2023/12/4 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一文读懂背包问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


轉自:劉毅

https://www.61mon.com/index.php/archives/188/


問題展開


有 N 件物品和一個容量為 V 的背包。第 i 件物品的體積是 Ci,其價值是 Wi。求解,在不超過背包容量情況下,將哪些物品裝入背包可使價值總和最大。


基本思路


這是最基礎的背包問題,特點是:每種物品僅有一件。


狀態 F[i,v] 表示前 i 件物品中選擇若干件放在容量為 v 的背包中,可以取得的最大價值。


轉移方程:



對于第 i 件物品,有放與不放兩種選擇。若選擇不放,F[i,v]=F[i?1,v];若選擇放,v?Ci 確保有足夠的空間,隨之 F[i,v]=F[i?1,v?Ci]+Wi。


代碼展開


/**

?*

?* author 劉毅(Limer)

?* date? ?2017-03-17

?* mode? ?C++

?*/

#include <iostream>

#include <algorithm>

using namespace std;

int main()

{

? ? const int N = 6;? ? ? ? ? ? ? ? ? ? ?// 物品個數

? ? const int V = 10;? ? ? ? ? ? ? ? ? ? // 背包體積

? ? ?// 第 i 個物品的體積(下標從 1 開始)

? ? int C[N + 1] = { -1,5,6,5,1,19,7 };?

? ? ?// 第 i 個物品的價值

? ? int W[N + 1] = { -1,2,3,1,4,6,5 };? ?

? ???// 狀態

? ? int F[N + 1][V + 1] = { 0 };? ? ? ??

? ? // 對于第 i 個物品

? ? for (int i = 1; i <= N; i++)?

? ? ? ? for (int v = 0; v <= V; v++)

? ? ? ? {

? ? ? ? ? ? F[i][v] = F[i - 1][v];? //第 i 個不放

? ? ? ? ? ??// 如果比它大,再放第 i 個

? ? ? ? ? ? if (v - C[i] >= 0 && F[i][v] < F[i - 1][v - C[i]] + W[i])?? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? ? ?F[i][v] = F[i - 1][v - C[i]] + W[i];

? ? ? ? }

? ? cout<< F[N][V] << endl;??

? ? return 0;

}


以上方法的時間和空間復雜度均為 O(VN),其中時間復雜度應該已經不能再優化了,但空間復雜度卻可以優化到 O(V)。


先考慮上面講的基本思路如何實現,肯定是有一個主循環i ← 1 to N,每次算出來二維數組 F[i,v] 的所有值。


那么,如果只用一個數組 F[v] 能不能保證第 i 次循環結束后 F[v] 中表示的就是我們定義的狀態 F[i,v] 呢?


F[i,v] 是由 F[i?1,v] 和 F[i?1,v?Ci] 兩個子問題遞推而來,能否保證在推 F[i,v] 時(也即在第 i 次主循環中推 F[v] 時)能夠取用 F[i?1,v] 和 F[i?1,v?Ci] 的值呢?


事實上,這要求在每次主循環中我們以v ← V to C[i]的遞減順序計算 F[v],這樣才能保證計算 F[v] 時 F[v?Ci] 保存的是狀態 F[i?1,v?Ci] 的值。


優化后的代碼如下:


/**

?*

?* author 劉毅(Limer)

?* date? ?2017-03-17

?* mode? ?C++

?*/

#include <iostream>

#include <algorithm>

using namespace std;

int main()

{

? ? const int N = 6;? ? ? ? ? ? ? ? ? ? ?// 物品個數

? ? const int V = 10;? ? ? ? ? ? ? ? ? ? // 背包體積

? ? // 第 i 個物品的體積(下標從 1 開始)

? ? int C[N + 1] = { -1,5,6,5,1,19,7 };??

? ??// 第 i 個物品的價值

? ? int W[N + 1] = { -1,2,3,1,4,6,5 };??

? ? int F[V + 1] = { 0 };? ? ? ? ? ? ? ? // 狀態

? ? for (int i = 1; i <= N; i++)? // 對于第 i 個物品

? ? ? ? for (int v = V; v >= C[i]; v--)

? ? ? ? ? ? F[v] = max(F[v], F[v - C[i]] + W[i]);

? ? cout << "最大價值是:" << F[V] << endl;??

? ? return 0;

}


初始化的細節問題


我們看到的求最優解的背包問題題目中,事實上有兩種不太相同的問法。有的題目要求 “恰好裝滿背包” 時的最優解,有的題目則并沒有要求必須把背包裝滿。


這兩種問法的實現方法只是在初始化的時候有所不同。


如果是第一種問法,要求恰好裝滿背包,那么在初始化時除了 F[0] 為 0,其它 F[1]...F[V] 均設為?∞,這樣就可以保證最終得到的 F[V] 是一種恰好裝滿背包的最優解。


如果并沒有要求必須把背包裝滿,而是只希望價格盡量大,初始化時應該將 F[0]...F[V] 全部設為 0。


這是為什么呢?可以這樣理解:初始化的 F 數組事實上就是在沒有任何物品可以放入背包時的合法狀態。


如果要求背包恰好裝滿,那么此時只有容量為 0 的背包可以在什么也不裝且價值為 0 的情況下被 “恰好裝滿”,其它容量的背包均沒有合法的解,屬于未定義的狀態,應該被賦值為 -∞了。


如果背包并非必須被裝滿,那么任何容量的背包都有一個合法解 “什么都不裝”,這個解的價值為 0,所以初始時狀態的值也就全部為 0 了。


參考文獻


背包九講。



總結

以上是生活随笔為你收集整理的一文读懂背包问题的全部內容,希望文章能夠幫你解決所遇到的問題。

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