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; }