Making the Grade(dp) POJ - 3666

题目大意:

      n个数字弄成非递增或者非递减的最小花费。

题目思路:

        首先我们想要改某座山的话,一定会改成是这群山里的某个的高度,如果改成一个中间的数值,那不就亏了吗,假如之前的山已经改好了,要改第 i 座山,如果这个比上一个小,为什么不把他改成这个呢,如果比后一个大,为啥不改成后边那个呢,(这里的后边,指的不是后边具体的那一座山,是指后边的最优情况)。

       本来想的是dp[i][j]表示第i个数改成 j 使得前i个递增的最小花费,但是这个第二维太大了,但是根据上边那一段话我们可以知道,第二维只需要把所有数据离散化掉就可以了,dp[i][j] 表示第i个数改成 第 j 个数使得前i个递增的最小花费。

                                                              b为离散化后数组,a为原来的数组

            dp[i][j] = abs( a[i] - b[j] ) + min(  dp[i-1][ k ]  )                       1  <=  k  <=  j

同理,非递增的话,我们把数组反过来,再次跑一边就可以了。

#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int MAXN = 1e5+5;
ll dp[2005][2005],dp2[2005][2005];
ll a[MAXN],b[MAXN],c[MAXN];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        c[n-i+1] = a[i];
        b[i] = a[i];
    }
    sort(b+1,b+1+n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            dp[i][j] = 1ll<<62;
            dp2[i][j] = 1ll<<62;
        }
    }
    for(int i=1;i<=n;i++){
        dp[0][i] = 0;
        dp2[0][i] = 0;
    }
    for(int i=1;i<=n;i++){
        ll Min = 1ll<<62;
        ll Min2 = 1ll<<62;
        for(int j=1;j<=n;j++){
            Min = min(Min,dp[i-1][j]);
            Min2 = min(Min,dp2[i-1][j]);
            dp[i][j] = min(dp[i][j],abs(a[i]-b[j]) + Min);
            dp2[i][j] = min(dp2[i][j],abs(c[i]-b[j])+Min);
        }
    }
    ll ans = 1ll<<62;
    for(int i=1;i<=n;i++){
        //cout<<dp[n][i]<<" * ";
        ans = min(ans,dp[n][i]);
        ans = min(ans,dp2[n][i]);
    }
    cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/qq_41645482/article/details/104216747