题目链接

错解:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const int N=2007;
int a[N];
int m[N][N]; // dp[i][j] 状态结尾的值
LL dp[N][N];// 前i个元素有序最大值小于等于a[j]的最值
int n;
int main ()
{
    while (~scanf ("%d",&n) ) {
        for (int i=1;i<=n;i++)
            scanf ("%d",&a[i]);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++) {
                m[i][j]=a[i];
                if (a[i]>a[j]) m[i][j]=a[j];
                if (a[i]<m[i-1][j]) m[i][j]=m[i-1][j];
                dp[i][j]=dp[i-1][j]+abs (a[i]-m[i][j]);
                cout<<"i: "<<i<<" j: "<<a[j]<<" "<<dp[i][j]<<endl;
            }
        LL ans=dp[n][1];
        for (int i=1;i<=n;i++)
            ans=min (ans,dp[n][i]);
        printf("%lld\n",ans);
    }
    return 0;
}
/* 错误的例子2 5 2 2 10 
因为定义的状态是 前n个元素小于等于a[j]的最小次数
dp[3][2](小于等于5)最优解有 2 5 5 和 2 2 2
这两个状态不能合并因为对后面的影响是不一样的
应该重新定义状态 dp[i][j]: 前n个元素有序最大元素是a[j]的最优解
*/

正解:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const int N=2007;
int a[N],b[N];
LL dp[N][N]; //前i个元素以a[j]结尾的最值
int n;
int main ()
{
    while (~scanf ("%d",&n)) {
        memset (dp,0x3f,sizeof(dp));
        for (int i=1;i<=n;i++) {
            scanf ("%d",&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]=abs(a[i]-b[j]);
                if (i!=1) dp[i][j]+=dp[i-1][j];
                dp[i][j]=min (dp[i][j-1],dp[i][j]);
            }
        printf("%d\n",dp[n][n]);
    }
    return 0;
}

对于动态规划的理解我还需要加强。。。