2024-02-10(动态规划-数字三角形模型)

898. 数字三角形 - AcWing题库

2024-02-06(线性DP、区间DP)-CSDN博客

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = 520;
        int INF = (int)1e9;
        int[][] a = new int[N][N];
        int[][] f = new int[N][N];
        
        int n = sc.nextInt();
        for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= i; j ++){
                a[i][j] = sc.nextInt();
            }
        }
        for(int i = 0; i <= n; i ++){
            Arrays.fill(f[i], -INF);
        }
        
        f[1][1] = a[1][1];
        
        for(int i = 2; i <= n; i ++){
            for(int j = 1; j <= i; j ++){
                f[i][j] = Math.max(f[i - 1][j - 1] + a[i][j], f[i - 1][j] + a[i][j]);
            }
        }
        
        int res = -INF;
        for(int i = 1; i <= n; i ++){
            res = Math.max(res, f[n][i]);
        }
        System.out.print(res);
    }
}

 1015. 摘花生 - AcWing题库

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        while(n -- > 0){
            int r = sc.nextInt();
            int c = sc.nextInt();
            int N = 110;
            int INF = (int)1e9;
            int[][] a = new int[N][N];
            int[][] f = new int[N][N];
            
            for(int i = 1; i <= r; i ++){
                for(int j = 1; j <= c; j ++){
                    a[i][j] = sc.nextInt();
                }
            }
            
            //这里和数字三角形模型不同的是数组f不用赋为无穷小
            f[1][1] = a[1][1];

            for(int i = 1; i <= r; i ++){
                for(int j = 1; j <= c; j ++){
                    //只能由左往右,由上往下
                    f[i][j] = Math.max(f[i - 1][j] + a[i][j], f[i][j - 1] + a[i][j]);
                }
            }
            System.out.println(f[r][c]);
        }
    }
}

1018. 最低通行费 - AcWing题库

        由于题目限制了商人必须在2n - 1的时间内走出去,也就是不走回头路,就是说只能往右走或者往下走,其实本质上和摘花生这个题是一样的。

        然后再考虑一下边界情况就可以了。

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int N = 110;
        int INF = (int)1e8;
        int[][] a = new int[N][N];
        int[][] f = new int[N][N];
        
        for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= n; j ++){
                a[i][j] = sc.nextInt();
            }
        }
        
        for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= n; j ++){
                if(i == 1 && j == 1){
                    f[i][j] = a[i][j];
                }else{
                    f[i][j] = INF;//因为要和自己比最小,所以一开始要赋值为最大
                    //如果i=1,那么就是只能是由左往右来走,执行第二条语句
                    //如果j=1,那么就是只能由上往下来走,执行第一条语句
                    //这里与摘花生不同的是要判断边界情况,然后把dp语句细化

                    //只有不在第一行的时候才可以从上面过来
                    if(i > 1) f[i][j] = Math.min(f[i][j], f[i - 1][j] + a[i][j]);
                    //只有不在第一列的时候才可以从左边过来
                    if(j > 1) f[i][j] = Math.min(f[i][j], f[i][j - 1] + a[i][j]);
                }
            }
        }
        System.out.print(f[n][n]);
    }
}

1027. 方格取数 - AcWing题库

只有在步数一样的时候才有可能踩到相同的格子。 

  

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = 15;
        int[][] w = new int[N][N];
        int[][][] f = new int[2 * N][N][N];
        
        int n = sc.nextInt();
        while(true){
            int a = sc.nextInt();
            int b = sc.nextInt();
            int c = sc.nextInt();
            if(a == 0 && b == 0 && c == 0) break;
            w[a][b] = c;
        }
        
        for(int k = 2; k <= n + n; k ++){
            for(int i1 = 1; i1 <= n; i1 ++){
                for(int i2 = 1; i2 <= n; i2 ++){
                    int j1 = k - i1;
                    int j2 = k - i2;
                    if(j1 >= 1 && j2 >= 1 && j2 <= n && j1 <= n){
                        int t = w[i1][j1];//如果重叠的话,就只加任意一个
                        if(j1 != j2) t += w[i2][j2];//否则两个点都加上
                        
                        //分别代表四种可能的情况
                        f[k][i1][i2] = Math.max(f[k][i1][i2], f[k - 1][i1 - 1][i2] + t);
                        f[k][i1][i2] = Math.max(f[k][i1][i2], f[k - 1][i1][i2] + t);
                        f[k][i1][i2] = Math.max(f[k][i1][i2], f[k - 1][i1 - 1][i2 - 1] + t);
                        f[k][i1][i2] = Math.max(f[k][i1][i2], f[k - 1][i1][i2 - 1] + t);
                    }
                }
            }
        }
        System.out.print(f[2 * n][n][n]);
    }
}

275. 传纸条 - AcWing题库

题目本质上和方格取数是一样的,只是矩阵不一样。

题目中要求从左上到右下,和右下到左上,其实都可以看作是 

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();
        int N = 60;
        int[][] w = new int[N][N];
        int[][][] f = new int[2 * N][N][N];
        //题目本质上和方格取数是一样的,只是一个是n×n矩阵,一个是m×n矩阵
        
        for(int i = 1; i <= m; i ++){
            for(int j = 1; j <= n; j ++){
                w[i][j] = sc.nextInt();
            }
        }
        
        for(int k = 2; k <= n + m; k ++){
            for(int i1 = 1; i1 <= m; i1 ++){
                for(int i2 = 1; i2 <= m; i2 ++){
                    int j1 = k - i1;
                    int j2 = k - i2;
                    if(j1 >= 1 && j2 >= 1 && j2 <= n && j1 <= n){
                        int t = w[i1][j1];
                        if(i1 != i2) t += w[i2][j2];
                        
                        f[k][i1][i2] = Math.max(f[k][i1][i2], f[k - 1][i1 - 1][i2] + t);
                        f[k][i1][i2] = Math.max(f[k][i1][i2], f[k - 1][i1][i2] + t);
                        f[k][i1][i2] = Math.max(f[k][i1][i2], f[k - 1][i1 - 1][i2 - 1] + t);
                        f[k][i1][i2] = Math.max(f[k][i1][i2], f[k - 1][i1][i2 - 1] + t);
                    }
                }
            }
        }
        System.out.print(f[m + n][m][m]);
    }
}

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值