日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SDNUOJ 1520.采药(多重背包问题)

發(fā)布時間:2023/12/14 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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背包多了一層循環(huán)枚舉這次選幾個,但要注意一定要加上能不能塞進去n個的判斷

#include<iostream> #include<cstring> using namespace std; int dp[1005]; int max(int x,int y) {return x>y?x:y; } int main() {int C;cin>>C;for(int i=1;i<=C;++i){memset(dp,0,sizeof(dp));int m,n;cin>>m>>n;int w,v,c;for(int j=1;j<=n;++j){cin>>w>>v>>c;for(int k=m;k>=w;--k){for(int p=1;p<=c&&p*w<=k;++p)//能不能塞進去p個的判斷一定要加 {dp[k]=max(dp[k],dp[k-w*p]+v*p);}}}cout<<dp[m]<<endl;}return 0; }

2.二進制優(yōu)化
再來一個經過二進制優(yōu)化過的方法,該方法的時間復雜度比上一個好了一些,是O(nnlog(2)n),該優(yōu)化方式實際上就是將每個物品能拿的個數進行了二進制分解,然后將分解后的那幾個分別當成獨立的物品,存到物品數組中,然后就是01背包問題了,為什么能保證每個容量的背包的解是正確的?因為一個數字進行二進制分解后,利用分解出來的數字的組合可以至少從1表示到那個數字,但是要注意如果是像10這樣無法完全進行二進制分解的數不要讓分解后的數組合后可以比它大,因為最多就能裝10件,多了裝不了,因此我們只要最后剩下一個不能用2的幾次方表示的數就行了,10可以分解為1,2,4,3,這些數經過組合可以表示出1-10中任意一個數。
下面是代碼:

#include<iostream> #include<cstring> using namespace std; int dp[1005]; struct data{int w;int v; }grass[1005];//存放物品的數組 int max(int x,int y) {return x>y?x:y; } int main() {int C;cin>>C;for(int i=1;i<=C;++i){int grassi=1;memset(dp,0,sizeof(dp));int m,n;cin>>m>>n;for(int j=1;j<=n;++j){int w,v,c;cin>>w>>v>>c;for(int k=1;k<=c;k*=2)//二進制拆分 ,拆分出來的當成一個獨立的物品 {c-=k;grass[grassi].v=v*k;grass[grassi++].w=w*k;}if(c>0)//將殘余情況的加進去 {grass[grassi].v=v*c;grass[grassi++].w=w*c;}}for(int i=1;i<grassi;++i){for(int j=m;j>=grass[i].w;--j){dp[j]=max(dp[j],dp[j-grass[i].w]+grass[i].v);//01背包 }}cout<<dp[m]<<endl;}return 0; }

3.單調隊列優(yōu)化

#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.采药(多重背包问题)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。