hdu3449
題意:
給定物品的組數n和一開始擁有的錢數m,後面n行輸入代表n組物品,若要購買該組物品中的乙個或多個都需要先購買盒子,盒子無價值,每組物品中最開始兩個數bp和mi分別表示盒子的**和該組物品的種數,問用m元最多可獲得貨物的最**值是多少。
思路:
典型的有依賴的0-1揹包問題,根據dd大牛的揹包九講,基本思路為先將每一組物品看作乙個集合,對第i組物品進行一次0-1揹包的選取,得到dp[i][j]即花j元在前i組物品中可獲得的最大價值,後再對dp[i-1][j]和dp[i][j] 再取一次最優解,dp[i-1][j]表示用j元情況下不選第i組中的物品,dp[i][j]表示選第i組物品下的最優解,選與不選取最優解dp[i][j]即為在j元下的最優解。
實現的細節問題:
首先選某組物品之前一定要選箱子,每組對應的箱子有**而無價值,為保證在對每一組物品進行選取討論時首先得選箱子,所以對於錢數j小於還是大於第i組箱子**的情況分開初始化:當擁有的錢j小於第i組箱子**bp的情況下dp[i][j]初始化為-1(非法狀態);而當擁有的錢j大於第i組箱子**bp的情況下dp[i][j]初始化為dp[i-1][j-bp] ( 需要保證在能購買第 i 組的箱子的情況下即錢數要先扣除買箱子的錢bp後,dp[i]陣列繼承dp[i-1]陣列的最優解 )。
另外在對於第i組物品進行0-1揹包討論的狀態轉移方程中取第i組的第k件物品dp[i][k-w] + v時要注意保證dp[i][k-w]合法,一方面需要保證k>w(**的迴圈條件中已經保證,很基礎的0-1揹包迴圈),另一方面討論dp[i][k-w]時要保證是在合法情況下討論亦即買了**為w的物品後要有餘額購買第i組的箱子bp,**中表現為dp[i][k-w] != -1。
hdu坑點吐槽:
需要多組樣例,這點題目中並未說明,而不加多組樣例會wa
#include
#include
#define ll long long
#define mem( f, x ) memset( f, x, sizeof( f ))
#define inf 0x3f3f3f3f
#define pii pair
using
namespace std;
const
int m =52;
const
int n =
100005
;int dp[m]
[n];
intmain()
for(
int j =
0; j <= m; j++
) dp[i]
[j]=
max( dp[i]
[j], dp[i-1]
[j]);}
printf
("%d\n"
, dp[n]
[m]);}
return0;
}
滾動陣列優化空間:
由上述**可以看出dp開了50*100005的空間但每一次i用到的只有dp[i]和dp[i-1]陣列,因此可以只開兩個陣列,乙個dp陣列儲存dp[i]陣列,另乙個f陣列儲存dp[i-1]陣列即可。另外需要注意的是當第i組結束後f陣列要將dp中的資料儲存下來作為下一輪的dp[i-1]使用,意為滾動。
#include
#include
#define ll long long
#define mem(f, x) memset( f, x, sizeof(f))
#define inf 0x3f3f3f3f
#define pii pair
using
namespace std;
const
int m =52;
const
int n =
100005
;int dp[n]
, f[n]
;int
main()
for(
int j =
0; j <= m; j++)}
printf
("%d\n"
, dp[m]);
}return0;
}
思路:將每個主件及其附件看作乙個集合(組),對問題進行劃分,對於第i組只有兩種情況:
(1). 不在第i組中取任何物品,這時直接繼承前i-1組的最優解即可。
(2). 取第i組中的某種組合,此時對第i組物品種的所有物品進行一次01揹包的討論即可,但是需要注意的是由於主件本身有一定的花費,所以對01揹包的第二重迴圈揹包的容量不能從全取,需要預留出主件的花費。因此揹包容量
for(j = m-bp…w)逆向迴圈,這裡可以看成在討論揹包容量j時預先扣除了主件大小pb,實際的總容量應是j = m … w + bp的逆迴圈,若以f陣列保留中間結果,則在取最終結果時dp[j]所對應的應該是f[j-bp],當下的dp[j]所對應的是前i-1組的最優解,f[j-bp]中儲存的是取第i組情況下的最優解,兩者再取一次最優解即可。
#include
#include
#define ll long long
#define inf 0x3f3f3f3f
#define mem( f, x ) memset( f, x, sizeof( f ) )
#define pii pair
#define fi first
#define se second
using
namespace std;
const
int m =
1e5+5;
const
int n =
1e5+5;
int m, n;
int dp[n]
, f[n]
;int
main()
for(
int j = bp; j <= m; j++
) dp[j]
=max
( dp[j]
, f[j-bp]);
}printf
("%d\n"
, dp[m]);
}return0;
}
有依賴的0 1揹包
考慮到每個主件最多只有兩個附件,因此我們可以通過轉化,把原問題轉化為01揹包問題來解決,在用01揹包之前我們需要對輸入資料進行處理,把每一種物品歸類,即 把每乙個主件和它的附件看作一類物品。處理好之後,我們就可以使用01揹包演算法了。在取某件物品時,我們只需要從以下四種方案中取最大的那種方案 只取主...
有依賴的01揹包問題
王強今天很開心,公司發給n元的年終獎。王強決定把年終獎用於購物,他把想買的物品分為兩類 主件與附件,附件是從屬於某個主件的,下表就是一些主件與附件的例子 主件附件 電腦印表機,掃瞄器 書櫃圖書 書桌檯燈,文具 工作椅無 如果要買歸類為附件的物品,必須先買該附件所屬的主件。每個主件可以有 0 個 1 ...
HDU1203(初識01揹包)
原題鏈結 01揹包是在m件物品取出若干件放在空間為w的揹包裡,每件物品的體積為w1,w2至wn,與之相對應的價值為p1,p2至pn。01揹包的約束條件是給定幾種物品,每種物品有且只有乙個,並且有權值和體積兩個屬性。因為每種物品只有乙個,對於每個物品只需要考慮選與不選兩種情況。hdu1203很明顯是一...