zoukankan      html  css  js  c++  java
  • DP(第二版)

    第一版请见:直通

    话不多说,直接上题

    1.P1040 加分二叉树

    直通

    思路:

      已知中序遍历,相当于一段区间了,所以我们枚举一个k,如果以k为根节点,能够将分数更新,那么这段区间的根节点就置为k,最后dp[1][n]就是得分;

      核心代码:

    	for(int i=n-1; i>=1; i--)
    		for(int j=i+1; j<=n; j++)
    			for(int k=i; k<=j; k++) 
    				if(dp[i][k-1]*dp[k+1][j]+a[k]>dp[i][j]) 
    					p[i][j]=k,dp[i][j]=dp[i][k-1]*dp[k+1][j]+a[k];
    

    坑点:

      别忘了dp数组的初始值为1,不然会“爆零”

    上代码:

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    const int M = 33;
    int n;
    int a[M],p[M][M],dp[M][M];
    
    void print(int l,int r) {
        if(l>r) return;
        printf("%d ",p[l][r]);
        print(l,p[l][r]-1);
        print(p[l][r]+1,r);
    }
    
    int main() {
        scanf("%d",&n);
        for(int i=0; i<=n; i++)
            for(int j=0; j<=n; j++)
                dp[i][j]=1;
        for(int i=1; i<=n; i++) {
            scanf("%d",&a[i]);
            dp[i][i]=a[i];
            p[i][i]=i;
        }
        for(int i=n-1; i>=1; i--)
            for(int j=i+1; j<=n; j++)
                for(int k=i; k<=j; k++) 
                    if(dp[i][k-1]*dp[k+1][j]+a[k]>dp[i][j]) 
                        p[i][j]=k,dp[i][j]=dp[i][k-1]*dp[k+1][j]+a[k];
        printf("%d
    ",dp[1][n]);
        print(1,n);
        return 0;
    }
    View Code

    2.P1052 过河

    直通

    思路:

      枚举左端点i,能够跳的步数j,以及st数组(存储是否有石头)

          那么转移方程就是:

            dp[i]=min(dp[i],dp[i-j]+st[i]);

      又因为是取min,所以需要进行初始化

    坑点:

      题目中说道:当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥

      所以我们最后进行输出的时候不能够只输出dp[l],而要在dp[l~l+t]之间进行取min

    上代码:

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int Mod = 2520; //1~10的最小公倍数,是路径压缩的关键!
    //因为2520步是它们的倍数,所以一定会直接跳过去,不用管是用多么大的步数跳的 
    const int L = 2333333; 
    int l,s,t,m,ans;
    int a[L],y[L],st[L],dp[L];
    //y[] : 压缩后每块石子之前需要跳的步数 
    
    int main() {
        scanf("%d%d%d%d",&l,&s,&t,&m);
        ans=m; //最多跳过m块石头 
        for(int i=1; i<=m; i++) scanf("%d",&a[i]);
        sort(a+1,a+1+m);
        for(int i=1; i<=m; i++) y[i]=(a[i]-a[i-1])%Mod; //状压 
        for(int i=1; i<=m; i++) a[i]=a[i-1]+y[i],st[a[i]]=1; //重新将a进行赋值,并标记石头 
        l=a[m]; //更新l值 
        for(int i=0; i<=l+m; i++) dp[i]=m; //赋对于该题来说的最大值m 
        dp[0]=0; //起点处不含石头 
        for(int i=s; i<l+t; i++)
            for(int j=s; j<=t; j++) //枚举跳的步数 
                if(i-j>=0) dp[i]=min(dp[i],dp[i-j]+st[i]); //dp转移方程 
        for(int i=l; i<l+t; i++) ans=min(ans,dp[i]); //最远跳到l+t 
        printf("%d",ans);
        return 0;
    }
    View Code

     

  • 相关阅读:
    10.1~10.15学习情况
    ACM-ICPC 2018 沈阳赛区网络预赛
    打卡4
    打卡3
    tab 简单的tab
    css 圆形动画
    pdf和图片之间的转换
    对list进行分组
    C# 打开所在文件夹
    读取xml文件
  • 原文地址:https://www.cnblogs.com/zxqxwnngztxx/p/7791509.html
Copyright © 2011-2022 走看看