POJ-3666 Making the Grade 【动态规划DP+滚动数组】

版权声明:本文为博主原创文章,转载请注明出处( • ̀ω•́ )✧ https://blog.csdn.net/wangws_sb/article/details/83756624

题目传送门

题目:输入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;
}

猜你喜欢

转载自blog.csdn.net/wangws_sb/article/details/83756624