1. 程式人生 > >POJ 3666 Making the Grade(二維DP)

POJ 3666 Making the Grade(二維DP)

題目連結:http://poj.org/problem?id=3666

題目大意:
給出長度為n的整數數列,每次可以將一個數加1或者減1,最少要多少次可以將其變成單調不降或者單調不增(題目BUG,只能求單調不降).
解題思路:
有一個結論,每次將數字X改成Y時,Y一定是出現過的,所以可以用雜湊減小資料範圍。
因為只用求單調不降,所以設dp[i][j]表示將1~i變為不降序列,且把第i個數改為第Hash[j]的最小花費 .
可以得到狀態轉移方程dp[i][j]=min(dp[i-1][1~j])+abs(Hash[j]-a[i])

程式碼

#include<iostream>
#include
<cstdio> #include<algorithm> #define LL long long using namespace std; const int N=2e3+5; LL a[N],dp[N][N],Hash[N];//dp[i][j]表示將1~i變為不降序列,且把第i個數改為第Hash[j]的最小花費 LL Abs(LL a){ return a>=0?a:-a; } int main(){ int n; cin>>n; for
(int i=1;i<=n;i++){ cin>>a[i]; Hash[i]=a[i]; } sort(Hash+1,Hash+1+n); int cnt=unique(Hash+1,Hash+1+n)-Hash; for(int j=1;j<cnt;j++){ dp[1][j]=Abs(Hash[j]-a[1]); } for(int i=2;i<=n;i++){ LL tmp=1e18; for(int
j=1;j<cnt;j++){ tmp=min(tmp,dp[i-1][j]); dp[i][j]=Abs(Hash[j]-a[i]); dp[i][j]+=tmp; } } LL ans=1e18; for(int j=1;j<cnt;j++) ans=min(ans,dp[n][j]); cout<<ans<<endl; return 0; }