已知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件商品, 你可以想到看看揹包能不能裝的下, 裝的下就要.如果你還是想不懂, 我想你或許付出的時間有點少了, 多付出點時間思考思考吧, 畢竟dp問題還是有些難度的.如果有2件商品, 你會想到看看能不能都裝下, 如果不能都裝下, 裝誰的時候價值最大.
如果有3件甚至更多的商品…
其實不難發現, 你自己模擬著模擬著, 你就找到了01揹包的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 團隊成員之間交流過少時,融合會經常出現問題,...