1. 程式人生 > >Making the Grade [POJ3666] [DP]

Making the Grade [POJ3666] [DP]

空間復雜度 def stack 一個表 序列 轉移 out pla color

題意:

給定一個序列,以最小代價將其變成單調不增或單調不減序列,代價為Σabs(i變化後-i變化前),序列長度<=2000,單個數字<=1e9

輸入:(第一行表示序列長度,之後一行一個表示序列第i的大小)

7
1
3
2
4
5
3
9
輸出:(代價) 3 分析: 這道題有bug,只要求單調不減序列 首先,對於這種問題,我們容易想到DP 記dp[i][j]為處理到i個,最高的為j 那我們的dp[i][j]=min(dp[i-1][k])+abs(j-h[i]) (k<=j) 但是顯然數字太大了,我們需要離散化 先把序列從小到大排序,存在另一個數組b[]裏
把j記成第j大的,那麽狀態轉移方程為dp[i][j]=min(dp[i-1][k])+abs(b[j]-h[i]) (k<=j) 這樣空間復雜度就夠了 但時間復雜度還不夠 我們仔細觀察可以發現,dp[i-1][k]的每次從1開始循環找最小值是浪費的 我們在j從小到大循環上來的時候,就記錄下最小值mn,那麽轉移方程就優化成dp[i][j]=mn+abs(b[j]-h[i]) 至此,本題解決。 (提示:開long long,inf要開大!) Code: 技術分享圖片
 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 ll 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<<30) 15 #define maxn 2005 16 using namespace std; 17 ll n; 18 ll a[maxn],b[maxn],dp[maxn][maxn]; 19 inline ll read() 20 { 21 ll x=0,f=1;char c=getchar(); 22 while(c<0||c>9){if(c==-)f=-1;c=getchar();} 23 while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} 24 return x*f; 25 } 26 27 void work() 28 { 29 rep(i,1,n) 30 { 31 ll mn=inf; 32 rep(j,1,n) 33 { 34 mn=min(mn,dp[i-1][j]); 35 dp[i][j]=(a[i]-b[j]>=0?a[i]-b[j]:b[j]-a[i])+mn; 36 } 37 } 38 ll ans=inf; 39 rep(i,1,n) ans=min(ans,dp[n][i]); 40 cout<<ans; 41 } 42 43 int main() 44 { 45 n=read(); 46 rep(i,1,n) a[i]=b[i]=read(); 47 sort(b+1,b+1+n); 48 work(); 49 return 0; 50 }
View Code

Making the Grade [POJ3666] [DP]