zoukankan      html  css  js  c++  java
  • CF 1013E Hills——隔项转移的DP

    题目:http://codeforces.com/contest/1013/problem/E

    设 dp[ i ][ j ][ 0/1 ] 表示前 i 个位置,有 j 个山峰,第 i 个位置不是/是山峰的最小代价。

    dp[ i ][ j ][ 0 ] 可以从 dp[ i-1 ][ j ][ 0/1 ] 转移,从 1 转移的话要调整成 a[ i ] <= a[ i-1 ] ,因为  i-1 是山峰,所以它的高度一定还是原高度 a[ i-1 ],从 0 转移没有要求。

    dp[ i ][ j ][ 1 ] 需要从 dp[ i-2 ][ j-1 ][ 0/1 ] 转移,这样才能知道  i-2 位置的高度到底是多少。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    
    const int N=5005;
    int n,a[N],dp[N][N][2];
    int main()
    {
      scanf("%d",&n);
      for(int i=1;i<=n;i++)scanf("%d",&a[i]);
      memset(dp,0x3f,sizeof dp);
      dp[0][0][0]=dp[1][0][0]=dp[1][1][1]=0;
      for(int i=2,lm=i+1>>1;i<=n;i++,lm=i+1>>1)
        for(int j=0;j<=lm;j++)
          {
        dp[i][j][0]=dp[i-1][j][0];
        int w=0; if(a[i]>=a[i-1])w=a[i]-a[i-1]+1;
        dp[i][j][0]=Mn(dp[i][j][0],dp[i-1][j][1]+w);
        if(!j)continue;
        dp[i][j][1]=dp[i-2][j-1][0];
        if(a[i-1]>=a[i])dp[i][j][1]+=a[i-1]-a[i]+1;
        w=0; if(a[i-1]>=a[i-2])w+=a[i-1]-a[i-2]+1;
        int tp=Mn(a[i-2]-1,a[i-1]);
        if(tp>=a[i])w+=tp-a[i]+1;
        dp[i][j][1]=Mn(dp[i][j][1],dp[i-2][j-1][1]+w);
          }
      /*
      for(int i=1,lm=i+1>>1;i<=n;i++,lm=i+1>>1)
        for(int j=0;j<=lm;j++)
          {
        dp[i][j][0]=dp[i-1][j][0];
        h[i][j][0]=a[i];
        int w;
        if(a[i]>=h[i-1][j][1])w=a[i]-h[i-1][j][1]+1;
        else w=0;
        if(dp[i-1][j][1]+w<dp[i][j][0])
          dp[i][j][0]=dp[i-1][j][1]+w,h[i][j][0]=h[i-1][j][1]-1;
    
        if(j)
          {
            dp[i][j][1]=dp[i-1][j-1][0];
            h[i][j][1]=a[i];
            if(h[i-1][j-1][0]>=a[i])
              dp[i][j][1]+=h[i-1][j-1][0]-a[i]+1;
          }
          }
      */
      for(int i=n+1>>1;i>=0;i--)
        {
          dp[n][i][0]=Mn(dp[n][i][0],dp[n][i][1]);
          dp[n][i][0]=Mn(dp[n][i][0],dp[n][i+1][0]);
        }
      for(int i=1,lm=n+1>>1;i<=lm;i++)
        printf("%d ",dp[n][i][0]);
      puts(""); return 0;
    }
    View Code

    自己原来还写了一个不是从 i-2 转移的,但带了一个 h[ i ][ j ][ 0/1 ] 表示当前的高度。这个 h[ ][ ][ ] 不参与转移,所以只是记录一下,不增加复杂度。但不知为何不对。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    
    const int N=5005;
    int n,a[N],dp[N][N][2],h[N][N][2];
    int main()
    {
      scanf("%d",&n);
      for(int i=1;i<=n;i++)scanf("%d",&a[i]);
      memset(dp,0x3f,sizeof dp);
      dp[0][0][0]=0;
      for(int i=1,lm=i+1>>1;i<=n;i++,lm=i+1>>1)
        for(int j=0;j<=lm;j++)
          {
        dp[i][j][0]=dp[i-1][j][0];
        h[i][j][0]=a[i];
        int w;
        if(a[i]>=h[i-1][j][1])w=a[i]-h[i-1][j][1]+1;
        else w=0;
        if(dp[i-1][j][1]+w<dp[i][j][0])
          dp[i][j][0]=dp[i-1][j][1]+w,
            h[i][j][0]=Mn(h[i][j][0],h[i-1][j][1]-1);//Mn
    
        if(j)
          {
            dp[i][j][1]=dp[i-1][j-1][0];
            h[i][j][1]=a[i];
            if(h[i-1][j-1][0]>=a[i])
              dp[i][j][1]+=h[i-1][j-1][0]-a[i]+1;
          }
          }
      for(int i=n+1>>1;i>=0;i--)
        {
          dp[n][i][0]=Mn(dp[n][i][0],dp[n][i][1]);
          dp[n][i][0]=Mn(dp[n][i][0],dp[n][i+1][0]);
        }
      for(int i=1,lm=n+1>>1;i<=lm;i++)
        printf("%d ",dp[n][i][0]);
      puts(""); return 0;
    }
    View Code
  • 相关阅读:
    格式化数字,将字符串格式的数字,如:1000000 改为 1 000 000 这种展示方式
    jquery图片裁剪插件
    前端开发采坑之安卓和ios的兼容问题
    页面消息提示,上下滚动
    可以使用css的方式让input不能输入文字吗?
    智慧农村“三网合一”云平台测绘 大数据 农业 信息平台 应急
    三维虚拟城市平台测绘 大数据 规划 三维 信息平台 智慧城市
    农业大数据“一张图”平台测绘 大数据 房产 国土 农业 信息平台
    应急管理管理局安全生产预警平台应急管理系统不动产登记 测绘 大数据 规划 科教 三维 信息平台
    地下综合管廊管理平台测绘 大数据 地下管线 三维 信息平台
  • 原文地址:https://www.cnblogs.com/Narh/p/10415626.html
Copyright © 2011-2022 走看看