• kuangbin 基础DP集合


    HDU 1024
    第一遍水过,没有体会到这个题的奥妙,思考了很久终于体会了。
    大概意思是求把序列分成m段的子序列,并不一定要覆盖完,求子序列和的最大值
    我们首先要写出基本的动态转移方程:
    DP:dp[ i ] [ j ] =max ( dp[ i - 1 ] [ 1~j-1 ]+a[ j ],dp[ i ] [ j - 1 ]+a[ j ] )
    其中dp[ i ][ j ]其中i,j表示,第i个集合,取前j 个数。
    意思是,dp[ i ][ j ]是由两个状态转移过来的,一个是把新的数归入i集合,还有一个是把新的数作为第一
    个数,归入新的集合。但是显然这个DP方程显得过于臃肿,我们想办法化简一下,我们发现,每次dp[i][j]
    都只和dp[i][j-1]以及dp[i-1][1~j-1]中的最大值有关,因此我们不妨把dp化简,用两个数组表示,now[j]数组表
    示当前a[j]在子序列中的最优值。pre[j]代表在上个序列中序列j最大值,在结合程序,也就比较好相通了。
    相当于now维护dp[ i ] [ j ],而pre[j]维护的是dp[i-1][j] 。

    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    const int maxn = 1e6+7;
    const int INF = 0x3f3f3f3f;
    int now[maxn];
    int a[maxn];
    int pre[maxn];
    int main(){
      int m,n;
      while(~scanf("%d%d",&m,&n)){
    
         for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
         }
         int maxx;
         memset(now,0,sizeof(now));
         memset(pre,0,sizeof(pre));
         for (int i=1;i<=m;i++){
            maxx=-INF;
            for (int j=i;j<=n;j++){
                now[j]=max(now[j-1]+a[j],pre[j-1]+a[j]);
                pre[j-1]=maxx;
                if(now[j]>maxx)maxx=now[j];
            }
         }
         printf("%d
    ",maxx);
      }
      return 0;
    }
    View Code

    还做到一个很类似的题目:
    把一段序列分成多个段,每个段最多k个,用每段的最大值替换每段里面的所有值。
    其实也是一个DP:
    maxx代表i-j内最大值,dp[j]=(dp[i-1]+maxx*(j-i+1),dp[j])
    这样就非常简单的了,我们想想为什么,因为首先我们要确定一定要维护一个区间的最大值,因此也要
    枚举区间,然后很容易写出转移方程。

    B-不说了。。。

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    const int maxx = 1e6+7;
    int a[maxx];
    int n;
    int main(){
      while(~scanf("%d",&n)){
         for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
         }
         sort(a+1,a+1+n);
         int ans=0;
         int last=a[1];
         int cnt=0;
         for (int i=1;i<=n;i++){
            if (last==a[i]){
                cnt++;
            }else {
               last=a[i];
               cnt=1;
            }
            if (ans<cnt){
                ans=a[i];
            }
         }
         printf("%d
    ",ans);
      }
      return 0;
    }
    View Code

    C-最长递增子序列问题翻版
    之间把所有可能的情况加入,按照X坐标排序后,写出限制条件,求最长的可能。
    dp[i]=max(dp[i],dp[j]+1) 其中j<i

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    struct node{
      int x,y,z;
    }a[200];
    int tot;
    void join(int x,int y,int z){
      a[++tot].x=x;
      a[tot].y=y;
      a[tot].z=z;
    }
    bool cmp(node a,node b){
       return a.x<b.x;
    }
    int dp[80];
    int main(){
      int n;
      int cas=1;
      while(~scanf("%d",&n)){
          if (n==0)break;
          int tmp[5];
          tot=0;
          memset(a,0,sizeof(a));
          for (int i=1;i<=n;i++){
            scanf("%d%d%d",&tmp[1],&tmp[2],&tmp[3]);
                join(tmp[1],tmp[2],tmp[3]);
                join(tmp[1],tmp[3],tmp[2]);
                join(tmp[2],tmp[1],tmp[3]);
                join(tmp[2],tmp[3],tmp[1]);
                join(tmp[3],tmp[1],tmp[2]);
                join(tmp[3],tmp[2],tmp[1]);
          }
          dp[0]=0;
          sort(a+1,a+1+tot,cmp);
          for (int i=1;i<=tot;i++){
              dp[i]=a[i].z;
              for (int j=i-1;j>=1;j--){
                if (a[j].x<a[i].x && a[j].y<a[i].y){
                dp[i]=max(dp[i],dp[j]+a[i].z);
                }
              }
          }
          int ans=0;
          for (int i=1;i<=tot;i++){
            ans=max(ans,dp[i]);
          }
          printf("Case %d: maximum height = %d
    ",cas++,ans);
      }
      return 0;
    }
    View Code

    D-经典的时间分配问题
    状压DP
    n种物品,枚举每一位的情况,用1-1<<n-1表示每一位是否存在,然后计算得分,然后维护dp[]最小,同时
    保存路径,由于是求字典序最小,我们需要把枚举顺序反向,然后最后反向输出结果即可,因为我们记录的
    是当前情况之前的情况,因此我们需要从最终情况开始往前找,找到前面即可,

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    const int maxx = 1<<15;
    const int INF = 0x3f3f3f3f;
    char name[20][120];
    int die[20];
    int fin[20];
    int dp[maxx];//到达当前状态所需要的最小得分
    int t[maxx];//做作业所需要花的时间
    int pre[maxx];//到达某个状态所需要完成的课程
    void output(int x){
       if (!x)return;
       output(x-(1<<pre[x]));
       printf("%s
    ",name[pre[x]]);
    }
    int main(){
      int ca;
      scanf("%d",&ca);
      int n;
      while(ca--){
        scanf("%d",&n);
        memset(t,0,sizeof(t));
        int bit=1<<n;
        for (int i=0;i<n;i++){
            scanf("%s%d%d",name[i],&die[i],&fin[i]);
        }
        for (int i=1;i<bit;i++){
            dp[i]=INF;
            for (int j=n-1;j>=0;j--){
                int temp=1<<j;//第j位的情况
                if((i&temp)==0)continue;//这一位没有被选到
                int score=t[i-temp]+fin[j]-die[j];
                if (score<0)score=0;
                if (dp[i]>dp[i-temp]+score){//把分最小化
                    dp[i]=dp[i-temp]+score;//更新为更小的
                    t[i]=t[i-temp]+fin[j];//达到状态t[i]所花的时间
                    pre[i]=j;//到达状态i的前驱
                }
            }
        }
        printf("%d
    ",dp[bit-1]);
        output(bit-1);
      }
      return 0;
    }
    View Code

    E Super Jumping! Jumping! Jumping!
    翻版最长递增子序列

    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #define LL long long
    using namespace std;
    int a[1008];
    LL dp[1008];
    int main(){
      int n;
      while(~scanf("%d",&n) && n){
         for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
         }
         memset(dp,0,sizeof(dp));
         for (int i=1;i<=n;i++){
            dp[i]=a[i];
            for (int j=i-1;j>=1;j--){
                if (a[i]>a[j])
                dp[i]=max(dp[i],dp[j]+a[i]);
            }
         }
         LL ans=0;
         for (int i=1;i<=n;i++){
            ans=max(ans,dp[i]);
         }
         printf("%lld
    ",ans);
      }
      return 0;
    }
    View Code

    F HDU - 1114
    完全背包+背包装满
    由于是求最小值,初始化为边界值,然后判断是否仍是边界值,从而判断是否装满,
    对于每个物品,枚举每个状态,并顺序枚举,这样每个状态可能用多次,从而达到完全背包的效果,反之
    01背包则不行,必须反向枚举,每个状态都只能由一个状态构成。

    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    int dp[10005];
    int p[505];
    int w[505];
    const int INF = 0x3f3f3f3f;
    int main(){
      int t;
      int E,F;
      scanf("%d",&t);
      while(t--){
         scanf("%d%d",&E,&F);
         int W=F-E;
         int n;
         scanf("%d",&n);
         memset(dp,0,sizeof(dp));
         for (int i=1;i<=n;i++){
            scanf("%d%d",&p[i],&w[i]);
         }
         for(int i=1;i<=W;i++){
            dp[i]=INF;
         }
         for (int i=1;i<=n;i++){
            for (int j=w[i];j<=W;j++){
                dp[j]=min(dp[j-w[i]]+p[i],dp[j]);
            }
         }
         if (dp[W]==INF){
            printf("This is impossible.
    ");
         }else {
            printf("The minimum amount of money in the piggy-bank is %d.
    ",dp[W]);
         }
      }
      return 0;
    }
    View Code

    G HDU - 1176
    数塔问题,从低到高反向求解

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    int a[100015][12];
    int dp[100015][12];
    int main(){
      int n;
      while(scanf("%d",&n)!=EOF && n){
         int tmp1,tmp2;
         int t=0;
         memset(a,0,sizeof(a));
         memset(dp,0,sizeof(dp));
         for (int i=1;i<=n;i++){
            scanf("%d%d",&tmp1,&tmp2);
            a[tmp2][tmp1]++;
            t=max(tmp2,t);
         }
         for (int i=0;i<=10;i++){
            dp[t][i]=a[t][i];
         }
         for (int i=t-1;i>=0;i--){
             for (int j=0;j<=10;j++){
                if (j==0)
                dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];
                else
                dp[i][j]=max(dp[i+1][j],max(dp[i+1][j-1],dp[i+1][j+1]))+a[i][j];
             }
         }
        printf("%d
    ",dp[0][5]);
      }
      return 0;
    }
    View Code

    H- HDU 1260
    简单DP,给出买一张,买相邻两张的价格,可以选择买一张或者买两张相邻的。
    转移方程
    dp[i]=max(dp[i-1]+one[i],dp[i-2]+two[i-1])

    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<stdio.h>
    using namespace std;
    int dp[2022];
    int one[2022];
    int two[2022];
    const int INF = 0x3f3f3f3f;
    int main(){
      int t;
      int n;
      scanf("%d",&t);
      while(t--){
        scanf("%d",&n);
        for (int i=1;i<=n;i++){
            scanf("%d",&one[i]);
        }
        for (int i=1;i<=n-1;i++){
            scanf("%d",&two[i]);
        }
        dp[1]=one[1];
        for (int i=2;i<=n;i++){
            dp[i]=min(dp[i-1]+one[i],dp[i-2]+two[i-1]);
        }
        int a=dp[n]/3600+8;
        int b=(dp[n]/60)%60;
        int c=dp[n]%60;
            if(a>12||(a==12&&(b>0||c>0)))
            printf("%.2d:%.2d:%.2d pm
    ",a,b,c);
            else
            printf("%.2d:%.2d:%.2d am
    ",a,b,c);
      }
      return 0;
    }
    View Code

    I-HDU 1257
    需要递减覆盖数目=最长递增子序列个数,因为没最长的递增子序列中的每个数,一定能把所有递减的序列
    给覆盖掉。

    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<stdio.h>
    using namespace std;
    int dp[10005];
    int h[10005];
    int main(){
       int n;
       while(~scanf("%d",&n)){
    
          for (int i=1;i<=n;i++){
            scanf("%d",&h[i]);
          }
          for (int i=1;i<=n;i++){
             dp[i]=1;
             for (int j=1;j<i;j++){
               if (h[i]>h[j]){
                 dp[i]=max(dp[i],dp[j]+1);
               }
             }
          }
         int ans=0;
         for (int i=1;i<=n;i++){
            ans=max(ans,dp[i]);
         }
         printf("%d
    ",ans);
       }
       return 0;
    }
    View Code

    J-HDU - 1160
    排序+最长递增子序列问题

    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<stdio.h>
    #include<stack>
    using namespace std;
    const int maxx = 1005;
    struct node
    {
        int w,s,id;
    } a[maxx];
    bool cmp1(node a,node b)
    {
        return a.w<b.w;
    }
    int dp[1005];
    int pre[1005];
    int ans[1005];
    int main()
    {
        int n=1;
        while(~scanf("%d%d",&a[n].w,&a[n].s))
        {
            a[n].id=n;
            n++;
        }
        memset(pre,-1,sizeof(pre));
        memset(dp,0,sizeof(dp));
        sort(a+1,a+n,cmp1);
        for (int i=1; i<n; i++)
        {
            dp[i]=1;
            for (int j=1; j<i; j++)
            {
                if (a[j].w<a[i].w && a[j].s>a[i].s){
                    if (dp[i]<dp[j]+1){
                        dp[i]=dp[j]+1;
                        pre[i]=j;
                    }
                }
            }
        }
    //    for (int i=1;i<n;i++){
    //        cout<<a[i].w<<" "<<a[i].id<<endl;
    //    }
        int maxx=0;
        int max_id;
        for (int i=1; i<n; i++)
        {
            if (maxx<dp[i])
            {
                maxx=dp[i];//
                max_id=i;//记录下最后面的那个的位置
            }
        }
        int p=max_id;
        printf("%d
    ",maxx);
        int cnt=1;
        while(p!=-1)
        {
            ans[cnt++]=a[p].id;
            //printf("%d
    ",a[p].id);
            p=pre[p];
        }
        for (int i=cnt-1;i>=1;i--){
            printf("%d
    ",ans[i]);
        }
        return 0;
    }
    View Code

    L-POJ - 1458
    最长公共序列问题
    用dp[i][j]表示,匹配到第i位和第j位时的最长递增公共序列的情况,
    转移方程
    第i位和第j位不匹配时
    dp[i][j]=max(dp[i-1][j]),dp[i][j-1])
    匹配时
    dp[i][j]=dp[i-1][j-1]+1;

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    char a[10005];
    char b[10005];
    int dp[1005][1005];
    int main(){
       while(~scanf("%s%s",&a,&b)){
        memset(dp,0,sizeof(dp));
        int n=strlen(a);
        int m=strlen(b);
        for (int i=1;i<=n;i++){
            for (int j=1;j<=m;j++){
              if (a[i-1]==b[j-1]){
                dp[i][j]=dp[i-1][j-1]+1;
              }else {
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
              }
            }
        }
        printf("%d
    ",dp[n][m]);
       }
       return 0;
    }
    View Code

    M-POJ - 1661
    高级版本数塔+排序
    dp[i][0]表示跑到第i层的左边,left表示下面层数的左边跑上来,right是表示下面层的右边跑上来
    dp[i][1]表示跑到第i层的右边
    dp[i][0]=min(dp[left][0]+a[i].l-a[left].l,dp[left][1]+a[left].r-a[i].l);
    dp[i][1]=min(dp[right][0]+a[i].r-a[right].l,dp[right][1]+a[right].r-a[i].r);

    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<stdio.h>
    #define LL long long
    using namespace std;
    struct node
    {
        int l,r,h;
    } a[1005];
    bool cmp(node a,node b)
    {
        return a.h<b.h;
    }
    int dp[1005][3];
    int main()
    {
        int t;
        scanf("%d",&t);
        int n,x,y,maxx;
        while(t--)
        {
            scanf("%d%d%d%d",&n,&x,&y,&maxx);
            a[0].l=x;
            a[0].r=x;
            a[0].h=y;
            memset(dp,0,sizeof(dp));
            for (int i=1; i<=n; i++)
            {
                scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].h);
                dp[i][0]=0x3f3f3f3f;
                dp[i][1]=0x3f3f3f3f;
            }
            sort(a,a+1+n,cmp);
            for (int i=0;i<=n;i++){
                int left=-1;
                int right=-1;
                for (int j=i-1;j>=0;j--){
                   if(left==-1 && maxx>=a[i].h-a[j].h && a[j].r>=a[i].l && a[j].l<=a[i].l){
                    left=j;
                   };
                   if(right==-1 && maxx>=a[i].h-a[j].h && a[j].r>=a[i].r && a[j].l<=a[i].r){
                    right=j;
                   }
                }
                if (left!=-1){
                    dp[i][0]=min(dp[left][0]+a[i].l-a[left].l,dp[left][1]+a[left].r-a[i].l);
                }else {
                    if (a[i].h<=maxx)dp[i][0]=0;
                }
                if (right!=-1){
                    dp[i][1]=min(dp[right][0]+a[i].r-a[right].l,dp[right][1]+a[right].r-a[i].r);
                }else{
                    if (a[i].h<=maxx)dp[i][1]=0;
                }
            }
            printf("%d
    ",dp[n][0]+y);
        }
        return 0;
    }
    View Code

    N-POJ 2533
    最长递增子序列

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    int a[1005];
    int dp[1005];
    int main(){
      int n;
      while(~scanf("%d",&n)){
         for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
         }
         memset(dp,0,sizeof(dp));
         for (int i=1;i<=n;i++){
            dp[i]=1;
            for (int j=1;j<i;j++){
                if (a[i]>a[j]){
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
         }
         int ans=0;
         for (int i=1;i<=n;i++){
            ans=max(ans,dp[i]);
         }
        printf("%d
    ",ans);
      }
      return 0;
    }
    View Code

    O-POJ 3186
    区间DP
    dp[i][j]选到代表从左往右第i个和从右往左第j个
    那么dp[i][j]=max(dp[i-1][j]+(i+j)*a[i],d[i][j-1]+(i+j)*a[n-j+1]);
    最后找出在dp[i][n-1]中最大值的即可。

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    int a[2006];
    int dp[2006][2006];
    int main(){
      int n;
      while(~scanf("%d",&n)){
         for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
         }
         for (int i=0;i<=n;i++){
            for (int j=0;j+i<=n;j++){
                if (i>0 && j>0){
                    dp[i][j]=max(dp[i-1][j]+(i+j)*a[i],dp[i][j-1]+(i+j)*a[n-j+1]);
                }else if (j>0){
                    dp[i][j]=dp[i][j-1]+j*a[n-j+1];
                }else if (i>0){
                    dp[i][j]=dp[i-1][j]+i*a[i];
                }
            }
         }
         int ans=0;
         for (int i=0;i<=n;i++){
            ans=max(dp[i][n-i],ans);
         }
         printf("%d
    ",ans);
      }
      return 0;
    }
    View Code

    P-HDU - 1078
    DFS+DP
    dp[i][j]=max(dp[i][j],dfs(i,j+k)+a[i][j]);
    dp[i][j]=max(dp[i][j],dfs(i+k,j)+a[i][j]);

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define rep(i,j,k) for(int i=j;i<=k;i++)
    using namespace std;
    int a[115][115];
    int dp[115][115];
    int n,k;
    int dfs(int x,int y)
    {
        if (dp[x][y])return dp[x][y];
        dp[x][y]=a[x][y];
        for (int i=1;i<=k;i++){
            if (x+i<=n && a[x+i][y]>a[x][y]){
                dp[x][y]=max(dp[x][y],dfs(x+i,y)+a[x][y]);
            }
            if (x-i>=1 && a[x-i][y]>a[x][y]){
                dp[x][y]=max(dp[x][y],dfs(x-i,y)+a[x][y]);
            }
            if (y+i<=n && a[x][y+i]>a[x][y]){
                dp[x][y]=max(dp[x][y],dfs(x,y+i)+a[x][y]);
            }
            if (y-i>=1 && a[x][y-i]>a[x][y]){
                dp[x][y]=max(dp[x][y],dfs(x,y-i)+a[x][y]);
            }
        }
        return dp[x][y];
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            memset(dp,0,sizeof(dp));
            scanf("%d",&k);
            if (n==-1 && k==-1)break;
            for (int i=1; i<=n; i++)
            {
                for (int j=1; j<=n; j++)
                {
                    scanf("%d",&a[i][j]);
                }
            }
            printf("%d
    ",dfs(1,1));
        }
        return 0;
    }
    View Code

    Q-HDU - 2859
    最大对称矩阵
    从左下角往右上角
    那么dp[i][j]=(dp[i-1][j+1]+1,dp[i][j])同时两边新增加的横和竖也要对称长度大于dp[i-1][j+1]
    否则就等于MIN(对称长度,dp[i-1][j+1])

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    int dp[1006][1006];
    int n;
    char a[1006][1006];
    int main(){
      int n;
      while(~scanf("%d",&n) && n){
    
         for (int i=0;i<n;i++){
            scanf("%s",a[i]);
         }
         int ans=0;
         for (int i=0;i<n;i++){
            for (int j=0;j<n;j++){
               dp[i][j]=1;
               int x=i;
               int y=j;
               while(x>=0 && y<n && a[x][j]==a[i][y]){
                 x--;
                 y++;
               }
               int len=i-x;
               if (len>dp[i-1][j+1]){
                 if (dp[i][j]<dp[i-1][j+1]+1)
                 dp[i][j]=dp[i-1][j+1]+1;
               }else {
                 dp[i][j]=len;
               }
               ans=max(ans,dp[i][j]);
            }
         }
         printf("%d
    ",ans);
      }
      return 0;
    }
    View Code

    R-POJ 3616
    翻版最长递增子序列

    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<stdio.h>
    #define LL long long
    using namespace std;
    struct node{
       LL s;
       LL en;
       LL ef;
    }a[2006];
    bool cmp(node a,node b){
      if (a.s==b.s){
        return a.en<b.en;
      }else {
        return a.s<b.s;
      }
    }
    LL dp[2006];
    int main(){
      int n,m,r;
      while(~scanf("%d%d%d",&n,&m,&r)){
        memset(dp,0,sizeof(dp));
        for (int i=1;i<=m;i++){
            scanf("%lld%lld%lld",&a[i].s,&a[i].en,&a[i].ef);
        }
        sort(a+1,a+1+m,cmp);
        for (int i=1;i<=m;i++){
            dp[i]=a[i].ef;
            for (int j=1;j<i;j++){
             //   cout<<a[i].s<<" "<<a[j].en<<endl;
                if(a[i].s>=a[j].en+r){
                    dp[i]=max(dp[i],dp[j]+a[i].ef);
                }
            }
        }
        LL ans=0;
        for (int i=1;i<=m;i++){
            ans=max(ans,dp[i]);
        }
        printf("%lld
    ",ans);
      }
      return 0;
    }
    View Code

    S-POJ 3666

    变成有序数列的最小代价
    dp[i][j]表示选到a[i]的时候,把a[i]变成数列中第j小的数。
    首先我们容易写出基本的DP
    dp[i][j]=abs(j-w[i])+min(dp[i-1][k]);(k<=j)
    表示选到i时,以j为最大值。
    他是由j-w[i]以及dp[i-1][k]中以k为最小值(k<=j)传来的
    那么我只需了,遍历时维护dp[i-1][k]=min即可
    方程也就写成了dp[i][j]=abs(a[i]-j)+min;
    最后把j离散化即可
    dp[i][j]=abs(a[i]-b[j])+min.其中b是a排序以后的值。
    相当于dp[i][j]是把a[i]变成b[j]再加上以前dp[i-1][k]的最小值。

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    const int N = 2005;
    int n;
    int a[N],b[N];
    long long dp[N][N];
    int main(){
      while(~scanf("%d",&n)){
    
        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++){
           long long mn=dp[i-1][1];
           for (int j=1;j<=n;j++)
           {
               mn=min(mn,dp[i-1][j]);
               dp[i][j]=abs(a[i]-b[j])+mn;
           }
        }
        long long ans=dp[n][1];
        for (int i=1;i<=n;i++){
            ans=min(ans,dp[n][i]);
        }
        printf("%lld
    ",ans);
      }
      return 0;
    }
    View Code
    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    SQL Server 用户管理:用 SQL 语句创建数据库用户(SQL Server 2005)
    主题:[Android API学习]AppWidget
    Android UriMatcher ContentUris
    Python的startswith和endswith
    Android编写测试数据库类时对AndroidMainfest文件进行配置
    Oracle数据库设置默认表空间问题
    Android 设置部分的字体的颜色
    Oralce函数经典 日期函数日期加减法
    PKU2593给出一串数字使得其中两个子段和最大
    边框小合集
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/10386890.html
Copyright © 2020-2023  润新知