深入理解动态规划

动态规划的核心:记住已经解决过的子问题的解

A * "1+1+1+1+1+1+1+1 =?" *

A : "上面等式的值是多少"
B : "8!"

A *在上面等式的左边写上 "1+" *
A : "此时等式的值为多少"
B : "9!"
A : "怎么这么快知道答案?"
A : "在8的基础上加1就行了"
A : "所以你不用重新计算因为你记住了第一个等式的值为8!动态规划算法也可以说是 '记住求过的解来节省时间'"

例题:

描述:

    7 
   3 8 
  8 1 0 
 2 7 4 4 
4 5 2 6 5 

上面显示了一个数字三角形。编写一个程序,计算从顶部开始到底部某处的路径上传递的最大数字总和。每个步骤可以沿对角线向下滑动,也可以沿斜向下滑动到右侧。 
输入

您的程序是从标准输入读取。第一行包含一个整数N:三角形中的行数。以下N行描述了三角形的数据。三角形中的行数> 1但<= 100.三角形中的数字全部为整数,介于0到99之间。
产量

你的程序是写入标准输出。最高总和写为整数。
样本输入

5
7
3 8
8 1 0 
2 7 4 4
4 5 2 6 5
输出:

30

递归解法:

import java.util.Scanner;

public class Main {
	public static final int size = 100;
	public static int a[][] = new int[size + 1][size + 1];
	public static int n;

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		n = s.nextInt();
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= i; j++) {
				a[i][j] = s.nextInt();
			}
		}
		System.out.println(MaxSum(1, 1));
	}

	private static int MaxSum(int i, int j) {
		// TODO 自动生成的方法存根
		if(i==n) {
			return a[i][j];
		}else {
			int x=MaxSum(i+1,j);
			int y=MaxSum(i+1,j+1);
			return Math.max(x, y)+a[i][j];
		}
	}
}

这段代码提交到POJ,显示运行超时,为什么呢?因为我们重复了大量的运算。

改进:每次计算好MaxSum(i,j)后,就把它保存起来,下次要用的时候直接拿出来用,不用再执行重复的运算。

package test;

import java.util.Scanner;

public class Main {
	public static final int size = 100;
	public static int a[][] = new int[size + 1][size + 1];
	public static int maxSum[][] = new int[size + 1][size + 1];
	public static int n;

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		n = s.nextInt();
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= i; j++) {
				a[i][j] = s.nextInt();
				maxSum[i][j]=-1;
			}
		}
		System.out.println(MaxSum(1, 1));
	}

	private static int MaxSum(int i, int j) {
		// TODO 自动生成的方法存根
		if(maxSum[i][j]!=-1) {
			return maxSum[i][j];
		}
		if(i==n) {
			return a[i][j];
		}else {
			int x=MaxSum(i+1,j);
			int y=MaxSum(i+1,j+1);
			maxSum[i][j]=Math.max(x, y)+a[i][j];
			return maxSum[i][j];
		}
	}
}

这次提交到POJ就Accept了

 

虽然Accept了,但是使用递归需要用到大量的堆栈,容易造成栈溢出,我们应该把递归改为动态规划。

右边的表怎么得到?

最后一行是 4 5 2 6 5 ,倒数第二行:2可以与4或5相加,明显5更大,5+2即为7,7可以和5或2相加,明显与5相加更大,5+7=12

以此类推。

倒数第三行:8可以与7或12相加,明显与12相加更大,即为20,以此类推。

 

动态规划解法:

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int n = s.nextInt();
		int a[][] = new int[n + 1][n + 1];
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= i; j++) {
				a[i][j] = s.nextInt();
			}
		}

		for(int i=n-1;i>0;i--) {
			for(int j=1;j<=i;j++) {
				a[i][j]=Math.max(a[i+1][j], a[i+1][j+1])+a[i][j];
			}
		}
		System.out.println(a[1][1]);
	}
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值