问题描述:
在数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。
路径上的每一步都只能往左下或 右下走。只需要求出这个最大和即可,不必给出具体路径。
三角形的行数大于1小于等于100,数字为 0 - 99输入格式:
输入格式:
5 //表示三角形的行数
接下来输入三角形
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
要求输出最大和
思路分析:
大致分为两种解决方法,一种是自上而下的解决,也就是使用dfs,穷尽所有情况,因为其中存在重叠子问题,故可以使用备忘录法进行解决。另一种是使用自下而上的方法,逐步的推导出结果,我们可以从最底层开始算起,让后逐步向上移动,在这个过程中,因为以前的数据无后座行,故可以使用一维滚动dp数组来进行计算,最终返回dp[0]即可。
具体见代码注释:
import java.util.Arrays;
import java.util.Scanner;
public class Szsjx {
//数字三角形
static int solve(int[][] b, int i, int j, int[][] c)//记忆型递归dfs
{
if (i == b.length || j == b.length) return 0;//递归出口
if (c[i][j] >= 0) return c[i][j];//先进行记忆数组查询
int temp = Math.max(b[i][j] + solve(b, i + 1, j, c), b[i][j] + solve(b, i + 1, j + 1, c));
c[i][j] = temp;//存入记忆数组
return temp;
}
static int dp(int[][] b)//动态规划解法
{
int row=b.length-1;//行数-1
int con=b[row].length-1;//列数-1
int []dp=new int[con+1];//形成dp滚动数组
for (int i = 0; i <dp.length ; i++) {//初始化一维滚动数组
dp[i]=b[row][i];
}
for (int i = row-1; i >=0 ; i--) {//更改一维滚动数组
for (int j = 0; j <=i ; j++) {
dp[j]=b[i][j]+Math.max(dp[j],dp[j+1]);
}
}
return dp[0];//返回dp【0】
}
public static void main(String[] args) {
Scanner a=new Scanner(System.in);
int n=a.nextInt();//输入对应的行数
int b[][]=new int[n][n];//数字三角形的输入
int [][]c=new int[n][n];//记忆数组
for (int i = 0; i <n ; i++) {//数组初始化
Arrays.fill(c[i],-1);
}
for (int i = 0; i <n ; i++) {//数字三角形输入
for (int j = 0; j <=i ; j++) {
b[i][j]=a.nextInt();
}
}
System.out.println("备忘录法结果");
System.out.println(solve(b,0,0,c));
System.out.println("备忘录数组");
for (int i = 0; i < n; i++) {//输出备忘录数组
System.out.println(Arrays.toString(c[i]));
}
System.out.println("动态规划结果");
System.out.println(dp(b));
}
}
运行结果如下: