题目
/*
* 7
* 3 8
* 8 1 0
* 2 7 4 4
*4 5 2 6 5
*数字三角形
*题目:
*在上面的三角形中,找一条从顶部到底边的路径,往左下或者右下走
*求路径所经过数字之和最大
*三角形行数1~100,数字为0~99
*
*输入:(以直角方式输入)
*5//行数
*7
*38
*810
*2744
*45265
*
注:输入时数字间有空格
1.递归(未记录每次MaxSum(r,j),多次重复计算)
*法1(时间复杂度很大)
*分析:
*1.用二维数组存放三角形D
*2.D(r,j)下一步D(r+1,j),或者D(r+1,j+1)
*3.MaxSum(r,j),从D(r,j)到底边各路径中最佳路径长
*递推式如下:
*if r==N MaSum(r,j)=D(r,j)
*if r<N MaxSum(r,j)=Max(MaxSum(r+1,j),MaxSum(r+1,j+1))+D(r,j)
*
*/
package dynamic_program;
import java.util.Scanner;
public class Test_11 {
public static int MaxSum(int i,int j)
{
if(i==n)
return D[i][j];
int x=MaxSum(i+1,j);
int y=MaxSum(i+1,j+1);
return Math.max(x, y)+D[i][j];
}
static int [][]D=new int [101][101];
static int n;
static Scanner in=new Scanner(System.in);
public static void main(String[] args) {
// TODO Auto-generated method stub
int i,j;
n=in.nextInt();
for(i=1; i<=n; i++)
for(j=1;j<=i;j++)
{
D[i][j]=in.nextInt();
}
System.out.println(MaxSum(1,1));
}
}
2.递归+动态规划(记录每个位置的Maxsum(r,j),避免重复计算)
package dynamic_program;
import java.util.Scanner;
/*
* 数字三角形法2
* 改进:
* 每算一个MaxSum(r,j)就保存起来,避免重复计算,MaxSum为二维数组
* 记忆递归型动态规划
*/
public class Test_12 {
public static int MaxSum(int i,int j)
{
if(maxSum[i][j]!=-1)
return maxSum[i][j];//已经被算过,直接返回
if(i==n)
maxSum[i][j]=D[i][j];
else{
int x=MaxSum(i+1,j);
int y=MaxSum(i+1,j+1);
maxSum[i][j]=Math.max(x, y)+D[i][j];
}
return maxSum[i][j];
}
static int D[][]=new int[101][101];
static int [][]maxSum=new int[101][101];
static int n;
static Scanner in=new Scanner(System.in);
public static void main(String[] args) {
// TODO Auto-generated method stub
int i,j;
n=in.nextInt();
for(i=1; i<=n; i++)
for(j=1;j<=i;j++)
{
D[i][j]=in.nextInt();
maxSum[i][j]=-1;//表示还没有被算出来
}
}
}
3.递归转递推,从底边往上推算
package dynamic_program;
import java.util.Scanner;
/*
* 数字三角形递归转递推,由已知推未知
* 自下而上的推算
* 优化1:用一维数组maxSum就可以存放,每次将上一行的最佳路径覆盖左下数据
* 优化2:直接用D数组的最后一行代替maxSum数组
*/
public class Test_13 {
//递推
static int D[][]=new int[101][101];
static int [][]maxSum=new int[101][101];
static int n;
static Scanner in=new Scanner(System.in);
public static void main(String[] args) {
// TODO Auto-generated method stub
int i,j;
n=in.nextInt();
for(i=1; i<=n; i++)
for(j=1;j<=i;j++)
{
D[i][j]=in.nextInt();
}
//最后一行的最佳路径即本身
for(i=1;i<=n;i++)
maxSum[n][i]=D[n][i];
for(i=n-1;i>=1;i--)
for(j=1;j<=i;j++)
maxSum[i][j]=Math.max(maxSum[i+1][j], maxSum[i+1][j+1])+D[i][j];
System.out.println(maxSum[1][1]);
}
}
public class Test_14 {
//优化1+优化2
static int D[][]=new int[101][101];
static int n;
static Scanner in=new Scanner(System.in);
public static void main(String[] args) {
// TODO Auto-generated method stub
int i,j;
n=in.nextInt();
for(i=1; i<=n; i++)
for(j=1;j<=i;j++)
{
D[i][j]=in.nextInt();
}
int []maxSum=D[n];
for(i=n-1;i>=1;i--)
for(j=1;j<=i;j++)
maxSum[j]=Math.max(maxSum[j], maxSum[j+1])+D[i][j];
System.out.println(maxSum[1]);
}
}
运行结果:
30
总结:动态规划适用于求最优解时,其子问题也是最优的情况,并且每一状态可以支撑其后状态(子问题可以支撑下一个问题的解决)