SDNUOJ 1520.采药(多重背包问题)
Time Limit: 1000 MS Memory Limit: 32768 KB
Description
SQK上山去采藥。SQK有一個容量為m(1<=m<=1000)的背包,他所采集的藥材的總重量不能大于背包的容量。已知共有n(1<=n<=100 )種藥材,每種藥材都有自己的價值,并且知道每種藥材的數量是有限的,如何選擇,才能使得背包中藥材價值最大?
Input
輸入數據首先包含一個正整數C(1<=C<=10),表示有C組測試用例,每組測試用例的第一行是兩個整數m和n(1<=m<=1000, 1<=n<=100),分別表背包的負重和藥材的種類,然后是n行數據,每行包含3個數w,v和c(1<=w<=100,1<=v<=200,1<=c<=100),分別表示每種藥材的重量、每株的價值以及對應種類藥材的株數。
Output
對于每組測試數據,請輸出能夠采集藥材的最大價值,每個實例的輸出占一行。
Sample Input
1
8 2
2 100 4
4 100 2
Sample Output
400
Source
2016_SunQianKun
1.暴力
先來最暴力的解法,時間復雜度為O(n^3),就是多了相較于01背包多了一層循環枚舉這次選幾個,但要注意一定要加上能不能塞進去n個的判斷。
2.二進制優化
再來一個經過二進制優化過的方法,該方法的時間復雜度比上一個好了一些,是O(nnlog(2)n),該優化方式實際上就是將每個物品能拿的個數進行了二進制分解,然后將分解后的那幾個分別當成獨立的物品,存到物品數組中,然后就是01背包問題了,為什么能保證每個容量的背包的解是正確的?因為一個數字進行二進制分解后,利用分解出來的數字的組合可以至少從1表示到那個數字,但是要注意如果是像10這樣無法完全進行二進制分解的數不要讓分解后的數組合后可以比它大,因為最多就能裝10件,多了裝不了,因此我們只要最后剩下一個不能用2的幾次方表示的數就行了,10可以分解為1,2,4,3,這些數經過組合可以表示出1-10中任意一個數。
下面是代碼:
3.單調隊列優化
#include<iostream> using namespace std; const int maxn=20005; int dp[maxn],que[maxn],book[maxn]; int max(int x,int y) {return x>y?x:y; } int main() {int W,N;cin>>N>>W;//N是有幾種物品,W是背包最多能容納的重量 for(int i=1;i<=N;++i){int w,v,c;cin>>w>>v>>c;//w是該物品的重量,v是該物品的價值,c是該物品最多能拿的數量 if(w*c>=W)//如果能拿的這一個物品拿最多的質量大于背包總共能裝的質量,就可以用完全背包問題來處理。 {for(int ind=w;ind<=W;++ind){dp[ind]=max(dp[ind],dp[ind-w]+v);}}else{for(int ind=0;ind<w;++ind){int head=0,tail=0;for(int jnd=0;jnd<=(W-ind)/w;++jnd){int temp=dp[ind+jnd*w]-jnd*v;while(head<tail&&que[tail-1]<=temp)--tail;book[tail]=jnd;que[tail++]=temp;if(book[head]<jnd-c)++head;dp[ind+jnd*w]=que[head]+jnd*v;}}}}cout<<dp[W]<<endl;return 0; }總結
以上是生活随笔為你收集整理的SDNUOJ 1520.采药(多重背包问题)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言科学计数法介绍和示例
- 下一篇: 英雄联盟官宣IG冠军皮肤原画 彩蛋是王思