0 1揹包問題

2022-09-10 06:42:15 字數 3452 閱讀 1952

給定n個物品和乙個揹包,物品\(i\)

\((1\le i \le n )\) 的重量為\(w_i\) ,其價值為\(v_i\) ,揹包容量為c,對每種物品只有兩種選擇:裝入揹包或者不裝。如何選擇裝入揹包的物品,使得裝入揹包的物品的總價值最大?

剛開始是我不是很理解這個容量是什麼意思,我以為是能裝多少個物品的意思,事實上這個容量的意思是,這個揹包所能過裝的最大重量。

所以,這個題目的意思是,我這個揹包只能裝這麼重的東西,我要怎麼裝,才能讓我帶走的東西價值最高。

我們可以這麼想,我們這些物品的子集全部找出來,然後再找出這些子集中重量和不超過c的,然後從中找到價值最大的子集,然後這個子集上的東西就是我要帶走的東西了。

但是,我們分析一下就會知道,對於n個物品,它的子集個數為\(2^n\) ,也就是說,它是呈指數趨勢增長的,如果我們的物品很多,那這樣產生的子集巨多,我們還按照上面的想法去幹顯然很呆。

然後,老師教我們用動態規劃去做,名詞聽起來就高階,然而我並不能理解動態規劃是個什麼思想,但這並不影響我去做這道題。也許學多一點以後就會知道了吧。那下面說一下我理解的思路:

我們把這些物品的重量用乙個陣列存起來,記為\(w[i]\)

把它們對應的價值也用乙個陣列存起來,記為\(v[i]\)

那下面我們先不考慮選哪些物品的問題,先找出這個最大的價值。

我們這樣子定義val(i,j),它表示將i個物品裝入容量為j的揹包所獲得的最大價值,至於裝哪些東西進揹包才能獲得最大價值,這就需要我們進行決策了。很明顯,這是我們01揹包問題的乙個子問題。我們假設前i-1個物品已經決策好了,現在來決策第i個物品,那我們現在是不是就只要考慮要不要把i裝入揹包就行了?如果把它裝入揹包後的價值變大,那我自然是把它裝進來呀,是吧。好,那麼我們寫一下在第i個位置的決策情況,我們來分析裝和不裝的情況下的價值:

如果當前剩餘的容量\(,不能裝入,當前價值等於前i-1個物品決策出來的價值,即\(val(i-1,j)\)

如果剩餘容量\(>w[i]\),我可以有裝入i和不裝這兩種選擇,我選哪種呢?那肯定做出價值大的那個選擇。如果不裝的話,當前價值就是:\(val(i,j)=val(i-1,j)\) ,也就是當前價值等於前i-1個物品決策出來的價值。如果選的話,那\(val(i,j)=val(i-1,j-w[i])+v[i]\) ,那當前價值相當於把前i-1個物品裝入j-w[i]容量的價值加上這個物品的價值。然後我們取上面兩種情況中價值大的作為決策依據。

也就是說,對第i個物品決策時,我的價值的情況如下:

好,那我現在得到一條遞推式了,我自然而然的就可以推出第i+1個物品在揹包剩餘容量已知的情況下的最佳決策,第i+2個物品的在揹包剩餘容量已知的情況下的最佳決策········一直可以推出,有n個物品,已知揹包剩餘容量為c的情況下的最佳決策,也就是最大價值,這是不是也就解決了我的問題?

其實還有乙個問題沒有解決,那就是我上面這條公式的起始情況是什麼?

不難發現,當我們決策第1 個物品時,我們要依賴前0個物品的決策結果,那我們來看第0個物品怎麼決策的,現在有0個物品,要把它們裝進容量為j的揹包,怎樣裝才能價值最大?顯然無論怎麼裝,價值都是0。

還有類似的,我有i個物品,把它們裝入到容量為0的揹包,價值當然也是0。那麼,起始情況如下:

val(0,j)=0;

val(i,0)=0;

那由上面的遞推關係,我們就可以求得\(val(n,c)\)的值了。

上面我們的到了決策的最大價值,那下面我們來看看到底那些物品被我們裝入了揹包:

我們回顧上面的內容,我們會發現,對於每乙個val(i,j)的值,我是不是都可以通過前乙個物品的決策結果得到,也就是說,對於每乙個val(i,j),我是不是都要存著,方便下乙個物品決策時參考?那我們用乙個二維陣列來存它們就剛剛好。

那經過上面那些決策,我們的二維陣列val[n+1][c+1]是不是就已經填好了?注意了,我這裡陣列大小為什麼是n+1c+1,因為我們上面把第0個物品和揹包容量為0,都算作正常情況,那0個物品也算作一種情況。當然,你也可以把它看作是一種初始化,我這麼講是為了方便理解。

好,那我的二維表已經填好了。那我們來判斷第i個物品有沒有裝入到揹包中,那我們是不是可以比較一下前i-1個物品在揹包容量為j時決策所得的價值和前i個物品在同種情況下的價值大小?如果val(i,j)=val(i-1,j)是不是說明,第i個物體沒有被裝入揹包啊,因為如果裝入的話,它的價值應該是比前乙個大的。那麼,我從後往前推是不是就可以判斷出哪些物品被裝入了揹包,哪些沒有?那到此為止,問題就解決了。

#include #include using namespace std;

int main()

for (int i = 1; i <= n; i++)

for (int i = 1; i <= n; i++)

}int x[n];

for (int j = c, i = n; i > 0; i--) else

x[i] = 0;

}cout << val[n][c] << endl;

for (int i = 1; i <= n; i++)

return 0;

}

主要算那個二重迴圈那裡,時間複雜度就是: \(o(n*c)\)

經過這篇部落格的寫作,我好像有一點理解動態規劃是個什麼概念了,大概就是當前的決策問題要依靠前面的決策結果才能作出決策,然後通過遞推關係式能夠得到最終的結果,這個好像又有點像遞迴,有點分不清。我想大概思想就是盡可能地利用中間過程的結果為下一步決策。具體的還沒有搞懂。

雖然有點理解揹包問題了,但是用文字描述出來總感覺怪怪的,好像就是有點表達不清楚的樣子,尤其是推最大價值那部分。希望以後能進一步改進一下,有大佬理解的話還希望能夠點撥一下,萬分感謝。

在編碼過程中要注意對資料進行初始化,不然會有你意想不到的結果,還有就是陣列不要越界,這同樣會發生不可預估的錯誤。在定義和使用w[n]v[n]以及val[n+1][c+1]時尤其要注意,從+1這個操作應該就會想到了。

揹包問題 01揹包問題

n個物品,總體積是v,每個物品的體積的vi,每個物品的最大價值是wi,在不超過v的體積下求最大價值 eg揹包容積為 5 物品數量為 4 物品的體積分別為 物品的價值分別為 思路定義乙個二位陣列int f new int n 1 v 1 f i j 就表示在1 i個物品中選取體積小於v的情況的最大價值...

揹包問題 01揹包

有n件物品和乙個容量為v的揹包。第i件物品的重量是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。01揹包中的 01 就是一種物品只有1件,你可以選擇放進去揹包即1,也可以選擇不放入揹包中即0。include include using namespace std const int ...

揹包問題(01揹包)

1085 揹包問題 在n件物品取出若干件放在容量為w的揹包裡,每件物品的體積為w1,w2 wn wi為整數 與之相對應的價值為p1,p2 pn pi為整數 求揹包能夠容納的最大價值。input 第1行,2個整數,n和w中間用空格隔開。n為物品的數量,w為揹包的容量。1 n 100,1 w 10000...