POJ-3666 Making the Grade 【動態規劃DP+滾動陣列】
阿新 • • 發佈:2018-11-19
題目:輸入n個數,第i個數字的值為a[i],把第i個數變為j的代價為a[i]-j的絕對值,求把這n個數組成的數列變成單調數列的最小代價。
題解:dp[i][j]表示前i個數最大值為b[j]時的最小代價,即第i個數在總數列中的值為第j小的時候的最小代價。
動態轉移方程:dp[i][j]=minn+Abs(a[i]-b[j])。
其中minn=min(dp[i-1][1],dp[i-1][2]......dp[i-1][j]),即第i個數在總序列中的值為第j小的時候的最小代價=第i-1個數在總序列中的值小於等於第j小的時候的最小代價 + 把第i個數變為在總數列中的值為第j小的時候的代價
用滾動陣列minn儲存第i-1個數在總序列中的值小於等於第j小的時候的最小代價。
結果序列可以是遞增序列也可以是遞減序列,可能是題目測試資料的問題,只考慮遞增序列就過了。
AC程式碼:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <queue> #include <stack> #include <vector> #include <map> #include <set> using namespace std; #define inf 0x7fffffff #define Abs(a) ((a)>0?(a):-(a)) typedef long long ll; const int maxn=2200; int n; ll a[maxn],b[maxn]; ll dp[maxn][maxn];//d[i][j] 代表前i個數最大為b[j]時的最小代價 int main() { scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+1+n); memset(dp,0,sizeof(dp)); for(int i=1; i<=n; i++) { ll minn=dp[i-1][1]; for(int j=1; j<=n; j++) { minn=min(minn,dp[i-1][j]); dp[i][j]=minn+Abs(a[i]-b[j]);//d[i][j]=min(d[i-1][k])+abs(a[i]-b[j]),(0<k<=j) } } ll ans=inf; for(int i=1; i<=n; i++) { ans=min(ans,dp[n][i]); } cout<<ans<<endl; return 0; }