• 动态规划----数字三角形问题


    题目:

      在数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或 右下走。只需要求出这个最大和即可,不必给出具体路径。三角形的行数大于1小于等于100,数字为 0 - 99。
      输入格式:

    5 //表示三角形的行数 接下来输入三角形
        7
       3 8
      8 1 0
     2 7 4 4
    4 5 2 6 5

      要求输出最大和。

    思路分析:

      这里的递归和记忆型递归都很容易理解,递归和记忆型递归都是自顶向下,动规则是自底向上,由小规模向上推。

      这里写dp方程的时候有一个思路,那就是依赖谁先求谁,这里依赖的是下一步的最大值,于是我们就可以先求出下一步的最大值,然后往上递推求出我们最终需要的值。我们可以用二维数组存储从最后一行开始每个路径的结果。

      那有些题目有空间大小的限制,这里就涉及到另一种技巧,滚动数组,滚动数组就是把本身需要保留的结果,但是利用过后直接用下一次的结果给覆盖掉,这样的一个数组就是滚动数组。

      滚动数组是DP中的一种编程思想。简单的理解就是让数组滚动起来,每次都使用固定的几个存储空间,来达到压缩,节省存储空间的作用。起到优化空间,主要应用在递推或动态规划中(如01背包问题)。因为DP题目是一个自底向上的扩展过程,我们常常需要用到的是连续的解,前面的解往往可以舍去。所以用滚动数组优化是很有效的。利用滚动数组的话在N很大的情况下可以达到压缩存储的作用

    代码:

    import java.time.Duration;
    import java.time.Instant;
    import java.util.Scanner;
    
    public class 数字三角形 {
    	public static void main(String[] args) {
    //		 int[][] triangle = {
    //		 {7},
    //		 {3, 8},
    //		 {8, 1, 0},
    //		 {2, 7, 4, 4},
    //		 {4, 5, 2, 6, 5},
    //		 {4, 5, 2, 6, 5, 7},
    //		 {4, 13, 12, 88, 6, 6, 5},
    //		 {3, 8, 7, 11, 9, 22, 66, 3},
    //		 };
    //		 Instant now = Instant.now();
    //		 System.out.println(maxSumUsingRecursive(triangle, 0, 0));
    //		 System.out.println("持续时间为:" +
    //				 Duration.ofMillis(Instant.now().toEpochMilli() -
    //				 now.toEpochMilli()).getSeconds());
    //		 
    //		 
    //		 now = Instant.now();
    //		 System.out.println(maxSumUsingMemory(triangle, 0, 0, new int[8][8]));
    //		 System.out.println("持续时间为:" +
    //				 Duration.ofMillis(Instant.now().toEpochMilli() -
    //				 now.toEpochMilli()).getSeconds());
    		Scanner sc = new Scanner(System.in);
    		int n = sc.nextInt();
    		int[][] triangle = new int[n][];
    		for (int i = 0; i < n; i++) {
    			triangle[i] = new int[i + 1];
    			for (int j = 0; j < i + 1; j++) {
    				triangle[i][j] = sc.nextInt();
    			}
    		}
    		System.out.println(maxSumUsingDp(triangle, 0, 0));
    	}
    
    	/**
    	 * @param triangle 数字三角形           
    	 * @param i 起点行号            
    	 * @param j 起点列号         
    	 * @return 计算出的最大和
    	 */
    	public static int maxSumUsingRecursive(int[][] triangle, int i, int j) {
    		int rowIndex = triangle.length;
    		if (i == rowIndex - 1) {
    			return triangle[i][j];
    		} else {
    			// 顶点的值+max(左侧支路的最大值,右侧支路的最大值)
    			return triangle[i][j]
    					+ Math.max(maxSumUsingRecursive(triangle, i + 1, j), maxSumUsingRecursive(triangle, i + 1, j + 1));
    		}
    	}
    
    	/**
    	 * 记忆型递归
    	 */
    	public static int maxSumUsingMemory(int[][] triangle, int i, int j, int[][] map) {
    		int rowIndex = triangle.length;
    		int value = triangle[i][j];
    		if (i == rowIndex - 1) {
    		} else {
    			// 缓存有值,便不递归
    			int v1 = map[i + 1][j];
    			if (v1 == 0) {
    				v1 = maxSumUsingMemory(triangle, i + 1, j, map);
    			}
    			// 缓存有值,便不递归
    			int v2 = map[i + 1][j + 1];
    			if (v2 == 0) {
    				v2 = maxSumUsingMemory(triangle, i + 1, j + 1, map);
    			}
    			value = value + Math.max(v1, v2);
    		}
    		// 放入缓存
    		map[i][j] = value;
    		return value;
    	}
    
    	// 滚动数组
    	public static int maxSumUsingDp(int[][] triangle, int i, int j) {
    		int rowCount = triangle.length;// 行数
    		int columnCount = triangle[rowCount - 1].length;// 最后一行的列数
    		int[] dp = new int[columnCount];
    		for (int k = 0; k < columnCount; k++) {
    			dp[k] = triangle[rowCount - 1][k];// 初始化最后一行
    		}
    
    		for (int k = rowCount - 2; k >= 0; k--) {
    			for (int l = 0; l <= k; l++) {
    				dp[l] = triangle[k][l] + Math.max(dp[l], dp[l + 1]);
    			}
    		}
    		return dp[0];
    	}
    }

    结果:

        

      路径为:7 3 8 7 5。

  • 相关阅读:
    Maven打jar包
    windows关闭占用某端口的进程
    windows系统下发布python模块到pypi
    【转】vmware 安装 osx 无法登录 appstore 的解决办法 (伪造smbios设备信息)
    【转】Java并发编程:volatile关键字解析
    自定义JSP标签
    不一样的ssm
    eclipse制作exe文件
    ftp服务器搭建及简单操作
    OC中的socket通信
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10368936.html
Copyright © 2020-2023  润新知