经典算法——数字三角形的三种解题方法:递推、记忆化搜索、动态规划

上题目链接:

http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/1730.html

 递推方法:

import java.util.Scanner;
//递推方法
/*
*  思路整理:
* 首先找出递推公式:
* arr[i][j] = arr[i][j] + max(arr[i+1][j],arr[i+1][j+1])  
* 
* 递推从下往上,一直计算到最上面的时候刚好是最大值
* 
* 数字三角形。如下图所示的数字三角形,从三角形的顶部到底部有很多条不同的路径。
对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。
编写一个程序求出最佳路径上的数字之和。
【注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。】
         7
       3   8
     8   1   2
   2   7   4   4
4    5   2   6   5
* 
*/
public class Triangle_recursion {
	public static void main(String[] args) {
		Scanner sn = new Scanner(System.in);
		int n = sn.nextInt();
		int[][] arr = new int[n][n];
		for(int i = 0;i < n;i++) {
			for(int j = 0;j <=i;j++) {
				arr[i][j] = sn.nextInt(); //数组初始化
			}
		}
		int k = n-1; //数组下标最大 n-1
		while(k > 0) { //k=0时不用计算
			for(int i = 0;i <= k-1;i++) {
				arr[k-1][i] += Math.max(arr[k][i],arr[k][i+1]);
			}
			k--;
		}
		System.out.println(arr[0][0]);		
		sn.close();
	}
}

记忆化搜索:

import static java.lang.Math.max;
import java.util.Scanner;
//记忆化搜索
/*
 *  思路整理:
* 
*                    v1 = 7+3+dfs(2,0)
* v1 = 7 + dfs(1,0)
*                    v2 = 7+3+dfs(2,1)
* 
* 
*                    v1 = 7+8+dfs(2,1)
* v2 = 7 + dfs(1,1)
                     v2 = 7+8+dfs(2,2)
                     
     且最终取得最大最小值,所以最终得到的就是整个和的最大值,dfs既然是递归思想,就一定会遍历到最后
*/
public class Triangle {
	static int n; //输入的常数n
	static int[][] triangle = new int[101][101]; //构造三角形
	static int[][] rec = new int[101][101];

	public static void main (String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		for(int i = 0; i < n; i++){
			for(int j = 0; j <= i; j++){
				triangle[i][j] = sc.nextInt();
				rec[i][j] = -1;  //对所有位置做标记
			}
		}
		
		int res = dfs(0, 0); //起点,从(0,0)开始
		System.out.println(res);
		
		sc.close();
	}
	
	public static int dfs(int row, int col){ //行 列
		if(row == n - 1){ //最后一行
			return triangle[row][col]; 
		}
		if(rec[row][col] > 0){ //当前位置被计算过
			return rec[row][col]; 
		}
		
		int v1 = triangle[row][col] + dfs(row + 1, col);
		int v2 = triangle[row][col] + dfs(row + 1, col + 1);
		//进行当前节点调用完的值的记录,比如2调用完毕那么这个时候需要记录下2这个节点对应的记录数组的值
		rec[row][col] = max(v1, v2);
		return rec[row][col];
	}
	 
}

动态规划方法:

import java.util.Scanner;

/* 动态规划方法 核心思想:将问题拆分为若干个子问题
*  
* 思路整理: 找出重叠的子问题
* 首先写出状态转移方程:
* arr[i][j] = arr[i][j] + max(arr[i+1][j],arr[i+1][j+1])  
* 
* 必须由上往下计算,计算得最后一排的数值成为所有路径的最大值,最后遍历最后一行,找出最大值中的最大值,即得所解
* 
*/
public class Triangle_DynamicProgramming {
	public static void main(String[] args) {
		Scanner sn = new Scanner(System.in);
		int n = sn.nextInt();
		int[][] arr = new int[n][n];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j <= i; j++) {
				arr[i][j] = sn.nextInt(); // 数组初始化
			}
		}
		// 利用动态规划特点:下一层的结果不影响上一层的结果,所以可以直接计算了将数组覆盖,不需要在new一个新的空间
		// 数组第一层不变
		for (int i = 1; i < n; i++) {
			for (int j = 0; j <= i; j++) { // 第二维
				if (j == 0) // 第一个数
					arr[i][j] += arr[i - 1][0];
				else if (j == i) // 最后一个数
					arr[i][j] += arr[i - 1][j - 1];
				else // 中间的所有数
					arr[i][j] += Math.max(arr[i - 1][j - 1], arr[i - 1][j]);
			}
		}
		int max = arr[n - 1][0];
		for (int i = 0; i < n; i++) {
			if (max < arr[n - 1][i])
				max = arr[n - 1][i];
		}
		System.out.println(max);
		sn.close();
	}
}

 

你可能感兴趣的:(算法)