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

输入格式:

5      //表示三角形的行数    接下来输入三角形

7

3   8

8   1   0

2   7   4   4

4   5   2   6   5

要求输出最大和

用递归解决很简单,从上到下遍历一边。

从第一行第一个开始寻找,判断左下或右下哪一个更大,用缓存数组提高效率

     if (i>=n||j>=n) {
return 0;
}
if (cache[i][j] != -1) {
return cache[i][j];
}
return cache[i][j]=Math.max(maxSum(i+1, j, n), maxSum(i+1,j+1,n))+num[i][j];

但是递归的效率很慢,不是一个好方法。

那么动态规划呢。

从下至上,首先计算最底层 。底层是无需计算的,保存即可。

下一步计算倒数第二层。

那么用循环就可以很简单的计算出最上面的第一行第一个即为所求

 public class POJ1163 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] num = new int[n][n];
int[][] cache = new int[n][n];
int i = 0;
while (i < n) {
int j = 0;
while (j <= i) {
num[i][j] = sc.nextInt();
j++;
}
i++;
}
for (int j = 0; j < n; j++) {
Arrays.fill(cache[j], -1);
}
long startTime=System.currentTimeMillis(); //获取开始时间
System.out.println(maxSum(0,0,n,cache,num));
long endTime=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(endTime-startTime)+"ms"); int[][] cal = new int[n][n];
startTime=System.currentTimeMillis(); //获取开始时间
for (i = 0; i < n; i++) {
cal[n-1][i] = num[n-1][i]; //保存最后一行就可以了
}
for ( i = n-2; i >= 0; i--) {
for (int j = 0; j <= i; j++) {
cal[i][j] = Math.max(cal[i+1][j], cal[i+1][j+1])+num[i][j];
}
}
System.out.println(cal[0][0]);
endTime=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(endTime-startTime)+"ms"); }
public static int maxSum(int i,int j, int n, int[][] cache,int [][] num) {
if (i>=n||j>=n) {
return 0;
}
if (cache[i][j] != -1) {
return cache[i][j];
}
return cache[i][j]=Math.max(maxSum(i+1, j, n,cache,num), maxSum(i+1, j+1,n,cache,num))+num[i][j];
} }

还有一种节省空间的方法 用一维数组保存最大值

     int[] cal1 = new int[n];
for (i = 0; i < n; i++) {
cal1[i] = num[n-1][i]; //sikao
}
for ( i = n-2; i >= 0; i--) {
for (int j = 0; j <= i; j++) {
cal1[j] = Math.max(cal1[j], cal1[j+1])+num[i][j];
}
}

接下来,我们就进行一下总结:

    递归到动规的一般转化方法

递归函数有n个参数,就定义一个n维的数组,数组的下标是递归函数参数的取值范围,数组元素的值是递归函数的返回值,这样就可以从边界值开始, 逐步填充数组,相当于计算递归函数值的逆过程。

    动规解题的一般思路

    1. 将原问题分解为子问题

  • 把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。子问题都解决,原问题即解决(数字三角形例)。
  • 子问题的解一旦求出就会被保存,所以每个子问题只需求 解一次。

    2.确定状态

  • 在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
  • 所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。 在数字三角形的例子里,一共有N×(N+1)/2个数字,所以这个问题的状态空间里一共就有N×(N+1)/2个状态。

整个问题的时间复杂度是状态数目乘以计算每个状态所需时间。在数字三角形里每个“状态”只需要经过一次,且在每个状态上作计算所花的时间都是和N无关的常数。

    3.确定一些初始状态(边界状态)的值

以“数字三角形”为例,初始状态就是底边数字,值就是底边数字值。

    4. 确定状态转移方程

定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。

数字三角形的状态转移方程:

    能用动规解决的问题的特点

1) 问题具有最优子结构性质。如果问题的最优解所包含的 子问题的解也是最优的,我们就称该问题具有最优子结 构性质。

2) 无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。

 

动态规划略有所得 数字三角形(POJ1163)的更多相关文章

  1. 动态规划之数字三角形(POJ1163)

    在下面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大.路径上的每一步都只能往左下或 右下走.只需要求出这个最大和即可,不必给出具体路径. 既然求目标问题是根据查表得来的,自然 ...

  2. 动态规划入门——数字三角形(Java)

    动态规划的概念对于新手来说枯燥难懂,就算看懂了,做题的时候依旧抓耳挠腮的毫无头绪,这些比较难理解的算法,还是需要根据例子来一步步学习和理解,从而熟练掌握,下面,咱们就通过一个简单的小例子来学习动态规划 ...

  3. dp递推 数字三角形,dp初学者概念总结

    数字三角形(POJ1163)          在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大.路径上的每一步都只能往左下或 右下走.只需要求出这个最大和即可,不必给出 ...

  4. hihoCoder #1037 : 数字三角形 (动态规划)

    题目链接:https://hihocoder.com/problemset/problem/1037# 问题描述 小Hi和小Ho在经历了螃蟹先生的任务之后被奖励了一次出国旅游的机会,于是他们来到了大洋 ...

  5. Problem C: 动态规划基础题目之数字三角形

    Problem C: 动态规划基础题目之数字三角形 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 208  Solved: 139[Submit][Sta ...

  6. [动态规划]数字三角形(版本I-III)

    level 1 1.1题目 1.1.1题目描述 考虑在下面被显示的数字金字塔. 写一个程序来计算从最高点开始在底部任意处结束的路径经过数字的和的最大.每一步可以走到左下方的点也可以到达右下方的点. 在 ...

  7. vijos 1006 晴天小猪历险记之Hill——数字三角形的终极变化

    题目链接:https://vijos.org/p/1006 数字三角形原题看这里:http://www.cnblogs.com/huashanqingzhu/p/7326837.html 背景 在很久 ...

  8. G:数字三角形

    总时间限制: 1000ms 内存限制: 65536kB描述73   88   1   02   7   4   44   5   2   6   5 (图1) 图1给出了一个数字三角形.从三角形的顶部 ...

  9. [TYVJ] P1044 数字三角形

    数字三角形 背景 Background 09年 USACO 11月月赛  铜牌第一道   描述 Description 示出了一个数字三角形. 请编一个程序计算从顶至底的某处的一条路径,使该路径所经过 ...

随机推荐

  1. Spark Streaming实时写入数据到HBase

    一.概述 在实时应用之中,难免会遇到往NoSql数据如HBase中写入数据的情景.题主在工作中遇到如下情景,需要实时查询某个设备ID对应的账号ID数量.踩过的坑也挺多,举其中之一,如一开始选择使用NE ...

  2. Windows编程坐标系统概念

    Windows编程中关于设置映象模式的四个函数 SetWindowOrgSetViewPortOrgSetMapModeSetWindowExtExSetViewPortExtEx 一.Windows ...

  3. js拉起或下载app

    产品提了个需求,通过手机网页判断是否安装了自己公司app,如果安装了则拉起app,没有安装则跳转到下载页. 经过各种查阅资料尝试总结了一个还算可以的办法. 拉起app的原理就是js和原生统一好一个地址 ...

  4. iOS上传代码到Github平台

    对于开发人员来说,很多时候想把自己好的代码 demo放到一个公共平台,与大家交流,Github就是一个不错的平台,下面给大家说说Github的具体使用方法. 第一步.申请Github账号.https: ...

  5. Linux实战教学笔记18:linux三剑客之awk精讲

    Linux三剑客之awk精讲(基础与进阶) 标签(空格分隔): Linux实战教学笔记-陈思齐 快捷跳转目录: * 第1章:awk基础入门 * 1.1:awk简介 * 1.2:学完awk你可以掌握: ...

  6. C++ 友元函数的函数指针

    成员函数的指针 讲友元之前先讲普通的成员函数的函数指针 class Std_interface { public: virtual void suspend() = 0; }; // define t ...

  7. loadrunner入门篇-Controller控制器

    Controller组件是LR的控制中心,主要包括场景设计和场景执行两部分.在VuGen中编辑完脚本并将脚本加载到Controller组件中,即开始对脚本运行时的场景进行设计,当场景设计完成后,即可执 ...

  8. MES项目参观交流会

    2016年11月10日,普实软件组织了河南蔚林.江苏正恺.吴通控股.上海锐拓等单位的26位企业家代表,走进科兴电器,开展企业家现场交流活动.企业家们参观了科兴花园式数字化工厂.感受了大数据中心的强大功 ...

  9. Linux下,Nginx的安装、升级及动态添加模块

    系统基于ubuntu server 14.04.4 amd64 安装 第一步 下载并解压Nginx压缩包 从Nginx官网下载Nginx,或者在Linux上执行wget http://nginx.or ...

  10. 如何配置多台mysql 服务器?

    当我们数据量增大时,数据库需要进行扩张时,或者做高可用,那么我们就需要用到同时多台mysql服务器.通过配置:可以实现,一台主mysql,负责记录数据的变化,多台从mysql,查询结果.修改文件:/w ...