Space Elevator [POJ2392] [DP][優化]
阿新 • • 發佈:2018-06-23
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 11View Code#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 }
Space Elevator [POJ2392] [DP][優化]