Bone Collector 01揹包問題 詳解

2021-10-02 18:35:02 字數 2669 閱讀 7472

已知n個糖果的重量和價值. 我們有乙個口袋, 最多可以裝v重量的糖果. 問口袋最多能放多少價值的糖果進去?

input

輸入的第一行是t, 表示有t組資料.

每組資料由三行組成.

第一行包含兩個整數n和v(n <= 1000, v <= 1000). n表示糖果的個數, v表示口袋的載重.

第二行包含n個整數, 表示每一顆糖果的價值.

第三行包含n個整數, 表示每一顆糖果的重量.

output

對每一組資料, 輸出口袋最終可以放進去糖果的價值.

sample input

15 10

1 2 3 4 5

5 4 3 2 1

sample output

14推薦大家去看看英文題目, 中文方便大家理解, 但是解題思路及**以英文題目為準.

這個題是動態規劃裡揹包問題中十分基礎的01揹包問題, 這裡不多說廢話了, 講解部分將放在**部分.

至於怎麼想到的dp思路, 在結尾也有一些個人淺顯的看法.

#include

#define ll long long

using

namespace std;

int w[

1005

], v[

1005];

//分別表示第i件商品的價值與體積

int dp[

1005][

1005];

//用於儲存結果, dp[i][j]. 表示可選購商品有i件, 揹包容量為j時的最優解

intmain

(void)}

printf

("%d\n"

, dp[n]

[m])

;//輸出 可選購的商品有n件, 揹包容量為m時的最優解

}return0;

}

其實我們可以由上述動態規劃公式我們可以得出乙個結論: 即我們當前所求狀態只與前乙個狀態有關, 那麼我們所開的dp陣列理論上而言只需要2 * 1005就可以了, 所以我們嘗試進行化簡.

#include

#define ll long long

using

namespace std;

int w[

1005

], v[

1005];

int dp[2]

[1005];

//注釋請參照版本一

intmain

(void)}

cout << dp[n %2]

[m]<< endl;

}return0;

}

#include

#define ll long long

using

namespace std;

int w[

1005

], v[

1005];

int dp[

1005];

intmain

(void

)//個人認為算是01揹包問題裡的最優寫法了吧... (**講解放下面)

} cout << dp[m]

<< endl;

}return0;

}

其實dp核心思路還是沒有變, 我們當前所求的狀態還是取決於前乙個狀態, 而二維->一維時, 我們需要保證當前需要的這個狀態是上乙個狀態留下來的, 而不是當前狀態改變後再次使用的.

如果我們直接對於版本2的**進行修改, 可以發現, 如果購買商品i時能取得優解, 則dp[j1]的狀態會被改變, 而在後續計算dp[j2]時, 我們就無法保證dp[j1]為前乙個狀態留下來的(j1 = j2 - v[i]).

但是如果倒著跑, 那就不會出現這種情況了, 因為即使我們改變了dp[j1]的值, 而在dp[j2]的計算中, 我們只會用到小於等於j2的部分, 而j1是》j2的.

同樣我們可以發現, 在版本1和版本2中, 如果當前揹包容量比v[i]要小的話, 我們的做法是直接把上乙個狀態複製到當前狀態, 並沒有做出改變. 而我們通過將j倒著去跑, 在條件判斷部分就讓j>=v[i]就很好優化了這一步的判斷.

如果你剛開始接觸, 我並不認為有人能一下子就能想到是動態規劃的思路, 但是你做過一次, 再做你就知道了.

如果你和我一樣想法有點較真, 那你可以看看***的說法:

這個題目已知一定是有最優解的, 無非就是買不買當前這個商品, 如果你把所有的解都列出來, 一定有最優解, 你可以考慮遞迴函式的思路. 缺點就是資料量一大, 電腦就跑不出來. 而跑不出來了, 我們就要想方法優化**.

如果只有1件商品, 你可以想到看看揹包能不能裝的下, 裝的下就要.

如果有2件商品, 你會想到看看能不能都裝下, 如果不能都裝下, 裝誰的時候價值最大.

如果有3件甚至更多的商品…

其實不難發現, 你自己模擬著模擬著, 你就找到了01揹包的dp公式, 你會想到從最簡單的狀態開始模擬, 記錄簡單狀態的每一種最優解. 隨著商品數量增加, 也要不斷改變最優解.

如果你還是想不懂, 我想你或許付出的時間有點少了, 多付出點時間思考思考吧, 畢竟dp問題還是有些難度的.

Bone Collector(複習01揹包)

傳送門 題目大意 01揹包裸題。複習01揹包 題目有n件物品和乙個容量為v的揹包。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。題解 include include include using namespace std int ...

天天寫演算法之Bone Collector

哇,本以為逃出了dp問題,結果轉身又掉了進去。我的腦子哇。這次是0 1揹包問題,感覺和我之前遇到的不太一樣,還沒有切實的編過程式。來看看哇。我一開始的思路是找單位體積價值最大的,進行填充,發現wa了,想了老一會,哦 原來是有可能乙個單位體積價值最大的,導致空間剩餘,使其在空間上變小。如果是可以分割的...

01《構建之法》閱讀筆記01

個人感受 我過去的做法 1 寫程式以實現功能為主要目的,所以有時候為了功能的保證,會不太注重演算法的使用。2 在團隊專案中,習慣了個人程式設計,和團隊成員溝通偏少。為什麼這樣不好 1 不注重演算法的使用,會無端的浪費空間和執行時間,使程式效率大大降低。2 團隊成員之間交流過少時,融合會經常出現問題,...