1. 程式人生 > >Space Elevator [POJ2392] [DP][優化]

Space Elevator [POJ2392] [DP][優化]

for sort div 使用 輸入 cout 不能 space ace

題目大意

n件物品,第i件hi高,有ci件,最高的一件不能超過ai的高度。問最高能堆多高

輸入:

第一行,一個n

接下來每一行,為hi,ai,ci

輸出,最高堆多高

樣例輸入:

3
7 40 3
5 23 8
2 52 6

樣例輸出:

48 (從下到上:3個2號,3個1號,6個3號)

分析:

我們很容易想到要先放限制高度小的,那我們就先按限制高度從小到大排序。

然後我們可以發現,這個和多重背包很像,“物重”“價值”都為hi,數量為ci

設dp[i][j]為用前i件,花費高度j的盒子,最高能堆多高(顯然dp[][j]=j/0)。

那麽狀態轉移方程為dp[i][j]=max{dp[i-1][j-k*hi]+hi*k}其中限制條件是(dp[i-1][j-k*hi]!=0或j==k*hi )

但我們發現這個復雜度是不優秀的,我們需要降復雜度。

以下是優化方法{

我們知道,0/1背包和完全背包只需要改變循環方向就行了。

而完全背包從小到大循環就是保證了在更新了標號小的後,計算標號大的時候利用小的就可以使用更新後的值,從而實現“物品無限”。

而我們多重背包是有限的個數,如何在完全背包上動點手腳?

我們在dp[j]相對記錄一個usd[j]表示已經用了這個物品幾次了。

在保證條件dp[j-hi]!=0或j==hi 和dp[j-hi]+hi>dp[j]時

還需滿足usd[j-hi]+1<=ci,再把usd[j]更新成usd[j-hi]+1,這樣就能保證該物品使用次數小於等於ci。

最後輸出結果小心坑,找到第一個dp[i]不等於0,輸出;特判ans==0的情況

代碼:

技術分享圖片
 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<cmath>
 6 #include<cstdio>
 7 #include<cstring>
 8 #include<iostream>
 9 #include<algorithm>
10 #define RG register int
11
#define rep(i,a,b) for(RG i=a;i<=b;++i) 12 #define per(i,a,b) for(RG i=a;i>=b;--i) 13 #define ll long long 14 #define inf (1<<29) 15 #define maxn 405 16 #define maxm 40005 17 using namespace std; 18 int n; 19 int dp[maxm],usd[maxm]; 20 struct Dat{ 21 int w,a,c; 22 inline int operator < (const Dat &tt)const{ 23 return a<tt.a; 24 } 25 }p[maxn]; 26 inline int read() 27 { 28 int x=0,f=1;char c=getchar(); 29 while(c<0||c>9){if(c==-)f=-1;c=getchar();} 30 while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} 31 return x*f; 32 } 33 int main() 34 { 35 n=read(); 36 int mx=0; 37 rep(i,1,n) p[i].w=read(),p[i].a=read(),p[i].c=read(); 38 sort(p+1,p+1+n); 39 rep(i,1,n) 40 { 41 memset(usd,0,sizeof(usd)); 42 rep(j,p[i].w,p[i].a) 43 if((j==p[i].w||dp[j-p[i].w]) && dp[j-p[i].w]+p[i].w>dp[j] && usd[j-p[i].w]+1<=p[i].c) 44 dp[j]=dp[j-p[i].w]+p[i].w, 45 usd[j]=usd[j-p[i].w]+1; 46 } 47 per(i,p[n].a,1) if(dp[i]){cout<<dp[i];return 0;} 48 puts("0"); 49 return 0; 50 }
View Code

Space Elevator [POJ2392] [DP][優化]