• 这个DP有点东西


    AcWing 271. 杨老师的照相排列

    状态表示:f[i][j][k][p][q]即每排分别i、j、k、p、q人,且i>=j>=k>=p>=q

    属性:cnt

    状态计算:从高到低给学生安排位置,考虑最后一个学生的位置

    #include<bits/stdc++.h>
    #define ll long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e6+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;
        char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
        return res*f;
    }
    
    int n,a[6];
    ll f[31][31][31][31][31];
    
    signed main() {
        while(~scanf("%lld",&n)&&n) {
            a[1]=a[2]=a[3]=a[4]=a[5]=0;//Attention!
            for(R i=1;i<=n;++i) a[i]=read();
            memset(f,0,sizeof f);
            f[0][0][0][0][0]=1;
            for(R i=0;i<=a[1];++i)
                for(R j=0;j<=min(a[2],i);++j)
                    for(R k=0;k<=min(a[3],j);++k)
                        for(R p=0;p<=min(a[4],k);++p)
                            for(R q=0;q<=min(a[5],p);++q) {
                                ll &x=f[i][j][k][p][q];
                                if(i&&i-1>=j) x+=f[i-1][j][k][p][q];
                                if(j&&j-1>=k) x+=f[i][j-1][k][p][q];
                                if(k&&k-1>=p) x+=f[i][j][k-1][p][q];
                                if(p&&p-1>=q) x+=f[i][j][k][p-1][q];
                                if(q) x+=f[i][j][k][p][q-1];
                            }
            printf("%lld
    ",f[a[1]][a[2]][a[3]][a[4]][a[5]]);
        }
        return 0;
    }
    闫氏DP分析法(免费打广告)

    Acwing 272. 最长公共上升子序列

    状态表示:f[i][j]即a[1~i]和b[1~j]的最长公共上升子序列长度,且以b[j]结尾

    属性:max

    状态转移:

    • 如果a[i]不在最长公共上升子序列中,则f[i][j]=f[i-1][j];
    • 如果a[i]在最长公共上升子序列中(即a[i]==b[j]),则考虑最长公共上升子序列中的倒数第二位是b[1~j-1]中的哪个
    #include<bits/stdc++.h>
    //#define int long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e6+5,inf=0x3f3f3f3f;
    
    IL int read() {
      int f=1;
      char ch;
      while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
      int res=ch-'0';
      while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
      return res*f;
    }
    
    int n,m,f[3005][3005];//以b[j]结尾 
    int a[3005],b[3005],ans;
    
    int main() {
      n=read();
      for(R i=1;i<=n;++i) a[i]=read();
      for(R i=1;i<=n;++i) b[i]=read();
      for(R i=1;i<=n;++i) {
          for(R j=1;j<=n;++j) {
                f[i][j]=f[i-1][j];//不包含a[i]
                if(a[i]==b[j]) {
                  f[i][j]=max(f[i][j],1);
                    for(R k=1;k<j;++k) {//枚举倒数第二个数 
                        if(a[i]>b[k]) 
                            f[i][j]=max(f[i][j],f[i-1][k]+1);
                    }
                }
            }
      }
      for(R i=1;i<=n;++i) ans=max(ans,f[n][i]);
      printf("%d",ans);
      return 0;
    }
    暴力枚举: Accepted 10/11

    仔细观察发现k循环非常多余,每次只多用到了一个b[j-1],故移出、特判

    #include<bits/stdc++.h>
    //#define int long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e6+5,inf=0x3f3f3f3f;
    
    IL int read() {
      int f=1;
      char ch;
      while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
      int res=ch-'0';
      while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
      return res*f;
    }
    
    int n,m,f[3005][3005];//以b[j]结尾 
    int a[3005],b[3005],ans;
    
    int main() {
      n=read();
      for(R i=1;i<=n;++i) a[i]=read();
      for(R i=1;i<=n;++i) b[i]=read();
      for(R i=1;i<=n;++i) {
        int ma=1;
        for(R j=1;j<=n;++j) {
                f[i][j]=f[i-1][j];//不包含a[i]
                if(a[i]>b[j-1]) ma=max(ma,f[i-1][j-1]+1);
                if(a[i]==b[j]) f[i][j]=max(f[i][j],ma);
            }
      }
      for(R i=1;i<=n;++i) ans=max(ans,f[n][i]);//别忘了循环b数组的每一个位置
      printf("%d",ans);
      return 0;
    }
    优化后代码

    Acwing 274. 移动服务

    状态表示:f[i][x][y]表示完成了前i个请求,其中一个员工位于pi,另外两个员工位于x和y时,公司当前最小花费

    属性:min

    状态计算:

    f[i+1,x,y]=min(f[i+1,x,y],f[i,x,y]+c(p1,pi+1))

    f[i+1,pi,y]=min(f[i+1,p1,y],f[i,x,y]+c(x,pi+1))

    f[i+1,x,pi]=min(f[i+1,x,pi],f[i,x,y]+c(y,pi+1))

    #include<bits/stdc++.h>
    //#define int long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e6+5,inf=0x3f3f3f3f;
    
    IL int read() {
      int f=1;
      char ch;
      while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
      int res=ch-'0';
      while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
      return res*f;
    }
    
    int n,l,a[205][205],f[1005][205][205],q[1005],ans=inf;
    
    int main() {
      l=read();n=read();
      for(R i=1;i<=l;++i)
        for(R j=1;j<=l;++j) 
            a[i][j]=read();
      for(R i=1;i<=n;++i) q[i]=read();
      memset(f,0x3f,sizeof f);
      f[0][1][2]=0;q[0]=3;
      for(R i=0;i<=n;++i) 
        for(R x=1;x<=l;++x)
            for(R y=1;y<=l;++y) {
                int v=f[i][x][y];
                int z=q[i],w=q[i+1];
                if(x==y||y==z||x==z) continue;
                f[i+1][x][y]=min(f[i+1][x][y],v+a[z][w]);
                f[i+1][z][y]=min(f[i+1][z][y],v+a[x][w]);
                f[i+1][x][z]=min(f[i+1][x][z],v+a[y][w]);
            }
      for(R x=1;x<=l;++x)
            for(R y=1;y<=l;++y) {
                int z=q[n];
                if(x==z||y==z||x==y) continue;      
            ans=min(ans,f[n][x][y]);
        }
      printf("%d",ans);
      return 0;
    }
    我把p数组写成了q数组

    Acwing 275. 传纸条

    状态表示:f[i][x1][x2]即走了i步之后,第一条路径在第x1行,第二条路径在第x2行时取得的数

    //x-1+y-1=i,故x1+y1=x2+y2=i+2,只要知道i和x就知道对应的y

    属性:max

    状态计算:

    每条路径有向右、向下两种扩展方法,故共有2*2=4种转移。以两条路径均往右扩展为例,其余三种情况同理。

    如果x1=x2并且y1+1=y2+1,那么两条路径进入同一个格子,只累加一次:f[i+1,x1,x2]=max(f[i+1,x1,x2],f[i,x1,x2]+a[x1,y1+1])

    否则两条路径分别扩展到不同的格子,两个格子中的数都进行累加:f[i+1,x1,x2]=max(f[i+1,x1,x2],f[i,x1,x2]+a[x1,y1+1]+a[x2,y2+1])

    初值为f[0,1,1]=a[1,1]

    目标为f[n+m-2,n,n]

    ——李煜东《算法竞赛进阶指南》

    //上面所说的n,m和Acwing题目中的相反

    #include<bits/stdc++.h>
    #define int long long
    #define ll long long
    #define IL inline
    #define R register int
    #define fa(x) a[x].fa
    #define ls(x) a[x].ch[0]
    #define rs(x) a[x].ch[1]
    
    using namespace std;
    const int N=1e6+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;
        char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
        return res*f;
    }
    
    int n,a[55][55],f[105][55][55],m;
    
    //f[i][x1][x2]
    //i+2=x+y
    //i:路径长度
    signed main() {
        m=read();n=read();
        for(R i=1;i<=m;++i)
            for(R j=1;j<=n;++j)
                a[i][j]=read();
        f[0][1][1]=a[1][1];
        for(R i=0;i<=n+m+2;++i)
            for(R x1=0;x1<=m;++x1)
                for(R x2=0;x2<=m;++x2) {
                    int y1=i+2-x1,y2=i+2-x2;
                    if(y1<1||y2<1) continue;//Attention!!
                    //down down
                    //right right
                    if(x1==x2) {
                        f[i+1][x1+1][x2+1]=max(f[i+1][x1+1][x2+1],f[i][x1][x2]+a[x1+1][y1]);
                        f[i+1][x1][x2]=max(f[i+1][x1][x2],f[i][x1][x2]+a[x1][y1+1]);
                    }
                    else {
                        f[i+1][x1+1][x2+1]=max(f[i+1][x1+1][x2+1],f[i][x1][x2]+a[x1+1][y1]+a[x2+1][y2]);
                        f[i+1][x1][x2]=max(f[i+1][x1][x2],f[i][x1][x2]+a[x1][y1+1]+a[x2][y2+1]);
                    }
                    //down right
                    if(x1+1==x2) f[i+1][x1+1][x2]=max(f[i+1][x1+1][x2],f[i][x1][x2]+a[x1+1][y1]);
                    else f[i+1][x1+1][x2]=max(f[i+1][x1+1][x2],f[i][x1][x2]+a[x1+1][y1]+a[x2][y2+1]);
                    //right down
                    if(x1==x2+1) f[i+1][x1][x2+1]=max(f[i+1][x1][x2+1],f[i][x1][x2]+a[x1][y1+1]);
                    else f[i+1][x1][x2+1]=max(f[i+1][x1][x2+1],f[i][x1][x2]+a[x1][y1+1]+a[x2+1][y2]);
                }
        printf("%lld",f[n+m+2][m][m]);
        return 0;
    }
    冗长的代码

    AcWing 273. 分级

    难点是证明b数组中的每一个数一定在a数组中出现过

    状态表示:f[i][j]即b[1~i]都已经安排好了且b[i]=a'[j](a'[]是排序后的a数组)

    属性:min

    状态计算:f[i][j]=min(f[i][j],f[i-1][k]+abs(a[i]-a'[j])),k从1~j循环,指b[i-1]对应的是a'[k]

    优化方式类似Acwing 272. 最长公共上升子序列

    #include<bits/stdc++.h>
    #define ll long long
    #define IL inline
    #define R register int
    using namespace std;
    const int N=1e6+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;
        char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
        return res*f;
    }
    
    int n,a[2005],b[2005],ans=inf,f[2005][2005];
    
    int main() {
        n=read();
        for(R i=1;i<=n;++i) b[i]=a[i]=read();
        sort(b+1,b+1+n);//递增
        for(R i=1;i<=n;++i) {
            int mi=inf;
            for(R j=1;j<=n;++j) {
                mi=min(f[i-1][j],mi);
                f[i][j]=mi+abs(a[i]-b[j]);
            }
        }
        for(R i=1;i<=n;++i) ans=min(ans,f[n][i]);
        reverse(b+1,b+1+n);//递减
        for(R i=1;i<=n;++i) {
            int mi=inf;
            for(R j=1;j<=n;++j) {
                mi=min(f[i-1][j],mi);
                f[i][j]=mi+abs(a[i]-b[j]);
            }
        }
        for(R i=1;i<=n;++i) ans=min(ans,f[n][i]);
        printf("%d",ans);
        return 0;
    }
    Acwing 273.
  • 相关阅读:
    百度云推送
    web请求报出 “超过了最大请求长度” 【注意:重启IIS】
    页面多个Jquery版本共存的冲突问题,解决方法!
    Web Api 中使用 PCM TO WAV 的语音操作
    Web Api 如何做上传文件的单元测试
    那些年收集的前端学习资源
    原创: 做一款属于自己风格的音乐播放器 (HTML5的Audio新特性)
    Web Api 接口文档制作
    如何在Asp.Net WebApi接口中,验证请求参数中是否携带token标识!
    JavaScript 面试题,给大家补补基础,加加油,埋埋坑!
  • 原文地址:https://www.cnblogs.com/ljy-endl/p/14584261.html
Copyright © 2020-2023  润新知