蓝桥杯 算法训练 最大值路径(动态规划)

蓝桥杯 算法训练 最大值路径(动态规划)

资源限制

时间限制:1.0s 内存限制:256.0MB


问题描述

刷微博,编程序。如下图所示,@北京发布 提出了如下“头脑震荡”问题。对此问题做一般化描述:
  有n阶方阵,从矩阵的左下角元素为起点,从行或列(水平或垂直)两个方向上移动,直到右上角。求出有多少条路径可以使得经过的元素累加值最大,最大值是多少。
蓝桥杯 算法训练 最大值路径(动态规划)_第1张图片


输入格式

共有n+1行。
  第一行整数n,表示矩阵的阶数,2<=n<=10。
  第二行起,每行n个整数,以空格分隔,共n行。


输出格式

一行,两个空格分隔的数,第一个表示最大值路径的条数,第二个表示最大值。


样例输入

5
4 5 4 5 6
2 6 5 4 6
2 6 6 5 2
4 5 2 2 5
5 2 5 6 4


样例输出

3 47


​ 首先这题很常规,和leetcode这道题很相似。https://leetcode-cn.com/problems/minimum-path-sum/,不过这题求的最大路径而已。难点在于还要输出最大值路径的条数,需要我们再返回去递归搜索。

确认dp数组的含义

​ 使用二维数组dp,其中dp[i][j]表示从左下角到第i+1行j+1列的最大值.最后答案就是dp[0][n-1]

找到状态转移方程

​ 因为只能从上面或者右边走,所以每一步的最大值就等于它左边的和下边的最大值再加上这地方本来的值。因此状态转移方程.

状态转移方程:dp[i][j]=Max(dp[i+1][j],dp[i][j-1])+nums[i][j].

填表赋初始值

​ 表格如下

i\j 0 1 2 3 4
0
1
2
3
4

​ 对于状态转移方程,对于最后一行和第一列是没办法填写的,需要我们手动赋初始值。起点即为本身的数值,剩下的最后一行走法只可能一直往右走,因为就是左边的相加对应的数值,第一列也是相似。因此填完初始值后如下。

i\j 0 1 2 3 4
0 17
1 13
2 11
3 9
4 5 7 12 18 22

​ 剩下的,我们需要根据状态转移方程从到数第二行开始填写,最后如下:

i\j 0 1 2 3 4
0 17 31 35 40 47
1 13 26 31 35 41
2 11 20 26 31 33
3 9 14 16 20 27
4 5 7 12 18 22
路径的总数

​ 这和以往的dp不同,还需要找相同路径的总数。我们定义为result,result初始值肯定为1,因为他必定有1条。然后我们需要从终点出发,dp[0][n-1],然后比较他的左边和下面,如果值相同的就result++,因为有说明有两条分支,其中一支已经就是result=1那支了,所以需要加1。如果不相同,就取最大那个值进行递归再查找分支。

最终代码
import java.util.Scanner;

/**
 * @author Meng
 * @date 2020/2/3
 */
public class Main {
    private static int n;
    private static int[][] dp;
    private static int result=1;

    /**
     * 递归查找最大值的路径总数
     * @param x
     * @param y
     */
    private static void total(int x, int y) {
        if(x+1>n-1||y-1<0){
            return;
        }
        if(x==n-1&&y==0){
            return;
        }
        if (dp[x][y - 1] > dp[x + 1][y]) {
            total(x, y - 1);
        } else if (dp[x][y - 1] < dp[x + 1][y]) {
            total(x + 1, y);
        }else{
            result++;
            total(x, y - 1);
            total(x + 1, y);
        }
    }


    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        int[][] arr = new int[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                arr[i][j] = scanner.nextInt();
            }
        }
        dp = new int[n][n];
        //起点赋初值
        dp[n - 1][0] = arr[n - 1][0];
        //第一列赋初始值
        for (int i = n - 2; i >= 0; i--) {
            dp[i][0] = arr[i][0] + dp[i + 1][0];
        }
        //最后一行赋初始值
        for (int i = 1; i < n; i++) {
            dp[n - 1][i] = arr[n - 1][i] + dp[n - 1][i - 1];
        }
        for (int i = n - 2; i >= 0; i--) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = Math.max(dp[i][j - 1], dp[i + 1][j]) + arr[i][j];
            }
        }
        //查找符合条件路径数量
        total(0,n-1);
        System.out.println(result + " " + dp[0][n - 1]);
    }
}

在这里插入图片描述

你可能感兴趣的:(java,数据结构与算法)