揹包九講 之 01揹包問題求具體方案

2021-10-03 12:33:14 字數 1817 閱讀 9302

本文基於01揹包問題

問題重述

有 n 件物品和乙個容量是 v 的揹包。每件物品只能使用一次。第 i 件物品的體積是 vi,價值是 wi。求解將哪些物品裝入揹包,可使這些物品的總體積不超過揹包容量,且總價值最大。

輸出 字典序最小的方案。這裡的字典序是指:所選物品的編號所構成的序列。物品的編號範圍是 1…n。

輸入格式

第一行兩個整數,n,v,用空格隔開,分別表示物品數量和揹包容積。

接下來有 n 行,每行兩個整數 vi,wi,用空格隔開,分別表示第 i 件物品的體積和價值。

輸出格式

輸出一行,包含若干個用空格隔開的整數,表示最優解中所選物品的編號序列,且該編號序列的字典序最小。

物品編號範圍是 1…n。

資料範圍

0思路分析:

01揹包那我們已經知道了,這個問題最為核心的狀態轉移方程是f[ i ][ j ] = max( f[ i -1][ j ] , f[ i-1 ][ j -v[i]]+wi ), 其表達的意思就是在當前物品選與不選的兩種狀態選擇其中較大的那種,這樣我們就能從中分離出乙個判斷式,即我們可以判斷出當前物品選沒選,如果選了或者說當前物品可以選(考慮到兩者相同的情況)那麼它就一定滿足f[ i ][ j ] == f[ i-1 ][ j -v[i]]+wi

回到本題我們需要確定我們的最優解選了那些物品,根據上述分析我們就可以在01揹包的最優解求出來後然後從n開始倒退檢查第i件物品可不可選,如果可選那麼我們就將其選定,然後減小體積繼續判斷,總結就是編號大的物品能選就選。這樣我們得到的方案物品編號就是字典序最大的因為我們選的是物品編號盡量大的物品。

然而題目中讓我們選出的是字典序最小的方案數,那麼目前我們的解是不符合題意的。至此我們思考為什麼我們只能選出物品編號盡量大的物品,因為我們的最優解是在判斷完最後乙個物品才得出的,而我們只有在拿到最優解之後,才能去判斷哪些物品可選。所以我們要想得到字典序最小的選擇序列,就必須使得最優解是在判斷完第乙個物品後得出的,那麼我們必須扭轉01揹包求解的思想,即判斷後從第n個物品向前開始判斷後幾個物品在不同體積下的最優解是什麼,最終得到後n個物品在體積v下的最優解。這樣我們就可以在判段判斷完第乙個物品後得到最優解,再用上述方式就能得到字典序最小的選擇方案。因為我們需要確定每乙個物品選沒選所以每步的資訊都需要保留,因此不能優化到一維求解,也不能現場輸入物品的體積和價值,只能用最初的求解方式。

c++**:

#include

using

namespace std;

int volume[

1010

],value[

1010];

//定義儲存物品體積和價值的陣列

int ans[

1010][

1010];

//定義儲存答案的陣列

int n,v;

intmain()

for(

int i=n;i>=

1;i--

)//從後往前遍歷物品求後幾個物品的最優解

}int nowvolume=v;

//記錄當前體積

for(

int i=

1;i<=n;i++

)//從第乙個物品開始遍歷

}return0;

}

揹包九講 01揹包問題

1 01揹包問題描述 已知 有 n 件物品和乙個容量為 v 的揹包。第i件物品的重量為w i 得到的價值是 c i 問題 求解將哪些物品裝入揹包可使價值總和最大。條件 每種物品只有一件,可以選擇放或者不放 2 基本思路 01揹包的特點 每種物品只有一件,可以選擇放或者不放 子問題定義狀態f i v ...

揹包九講之 01揹包

01揹包是最基礎的揹包問題,其中01代表的就是第i個物品的選或不選,在此先設v i 為體積,w i 為價值。很顯然,我們可以使用二位陣列dp i j 來表示前i個物品在揹包容量為j的時候可存放的最大價值。首先dp 0 0 0是很顯然的。而計算dp i j 時,存在01兩種情況 選或不選第i件物品。1...

揹包九講 之 01揹包求方案數

本文基於01揹包問題 問題重述 有 n 件物品和乙個容量是 v 的揹包。每件物品只能使用一次。第 i 件物品的體積是 vi,價值是 wi。求解將哪些物品裝入揹包,可使這些物品的總體積不超過揹包容量,且總價值最大。輸出 最優選法的方案數。注意答案可能很大,請輸出答案模 109 7 的結果。輸入格式 第...