The Triangle
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 38195   Accepted: 22946

Description

7
3 8
8 1 0
2 7 4 4
4 5 2 6 5 (Figure 1)

Figure 1 shows a number triangle. Write a program that calculates the highest sum of numbers passed on a route that starts at the top and ends somewhere on the base. Each step can go either diagonally down to the left or diagonally down to the right. 

Input

Your program is to read from standard input. The first line contains one integer N: the number of rows in the triangle. The following N lines describe the data of the triangle. The number of rows in the triangle is > 1 but <= 100. The numbers in the triangle,
all integers, are between 0 and 99.

Output

Your program is to write to standard output. The highest sum is written as an integer.

Sample Input

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

Sample Output

30

题意:

在上面的数字三角形中寻找一条从顶部究竟边的路径。使得

路径上所经过的数字之和最大。路径上的每一步都仅仅能往左下或

右下走。仅仅须要求出这个最大和就可以。不必给出详细路径。

三角形的行数大于1小于等于100,数字为 0 - 99

超级经典啊有木有,,理解动归必看啊有木有。

。。

解题思路:

用二维数组存放数字三角形。

D( r, j) : 第r行第 j 个数字(r,j从1開始算)

MaxSum(r, j) : 从D(r,j)究竟边的各条路径中,

最佳路径的数字之和。

问题:求 MaxSum(1,1)

典型的递归问题。

D(r, j)出发,下一步仅仅能走D(r+1,j)或者D(r+1, j+1)。

故对于N行的三角形:

if ( r == N)

MaxSum(r,j) = D(r,j)

else

MaxSum( r, j) = Max{ MaxSum(r+1,j), MaxSum(r+1,j+1) } + D(r,j)

数字三角形的递归程序:

#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;
int D[MAX][MAX];
int n;
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 max(x,y)+D[i][j];
} int main(){
int i,j;
cin >> n;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
cin >> D[i][j];
cout << MaxSum(1,1) << endl;
}

为什么超时?

回答:反复计算

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

假设採用递规的方法,深度遍历每条路径。存在大

量反复计算。则时间复杂度为 2 n ,对于 n = 100

行,肯定超时。

比方:当我们在计算第三行长度时。由于8 1 0的产生都基于第四行的”7“这个位置,即的D[4][2],又在进行路径搜索时前面共同拥有1*2*3条路径,这就会反复计算6*2次==12次。

考虑到假设能去除反复将会使得程序执行效率大大提高。

那么详细怎么做呢???

假设每算出一个MaxSum(r,j)就保存起来,下次用

到其值的时候直接取用,则可免去反复计算。

那么

能够用O(n 2 )时间完毕计算。由于三角形的数字总

数是 n(n+1)/2

数字三角形的记忆递归型动归程序:

#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX]; int n;
int maxSum[MAX][MAX];
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] = max(x,y)+ D[i][j];
}
return maxSum[i][j];
}
int main(){
int i,j;
cin >> n;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++) {
cin >> D[i][j];
maxSum[i][j] = -1;
}
cout << MaxSum(1,1) << endl;
}

若首先对最底层maxsum[n][j]进行赋值,那么就能够不断向上递推出最大值maxsum[1][1]。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDQ5MjYwOQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" align="middle" alt="">

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDQ5MjYwOQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" align="middle" alt="">

递推型动归程序:

#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX]; int n;
int maxSum[MAX][MAX];
int main() {
int i,j;
cin >> n;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
cin >> D[i][j];
for( int i = 1;i <= n; ++ i )
maxSum[n][i] = D[n][i];
for( int i = n-1; i>= 1; --i )
for( int j = 1; j <= i; ++j )
maxSum[i][j] = max(maxSum[i+1][j],maxSum[i+1][j+1]) + D[i][j]
cout << maxSum[1][1] << endl;
}

空间优化:

不是必需用二维maxSum数组存储每个MaxSum(r,j),仅仅要从底层一行行向上

递推。那么仅仅要一维数组maxSum[100]就可以,即仅仅要存储一行的MaxSum值就

能够。

想一下:详细情形是这种,依次选取相邻两个中最大的再加上D[i][j],那么新得到的数值将存储到数组中并覆盖这个相邻数的前一个,每经过一次i循环,数组被覆盖的数值逐渐降低,知道第二行相加覆盖第一行也就是第一个数组D[1].你会发现,仅仅有数组中的第n个数是没有改变的,。

看代码:

#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int n;
int maxSum[MAX];
int max(int a,int b)
{return a>b?a:b;}
int main() {
int i,j;
cin >> n;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
cin >> D[i][j];
for(i = 1;i <= n; ++ i )
maxSum[i] = D[n][i];
for(i = n-1; i>= 1; --i )
for(j = 1; j <= i; ++j )
maxSum[j] = max(maxSum[j],maxSum[j+1]) + D[i][j];
cout << maxSum[1] << endl;
return 0;
}

进一步考虑。连maxSum数组都能够不要,直接用D的

第n行替代maxSum就可以。

节省空间,时间复杂度不变

看代码:

#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int n; int * maxSum;
int main(){
int i,j;
cin >> n;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
cin >> D[i][j];
maxSum = D[n]; //maxSum指向第n行
for( int i = n-1; i>= 1; --i )
for( int j = 1; j <= i; ++j )
maxSum[j] = max(maxSum[j],maxSum[j+1]) + D[i][j];
cout << maxSum[1] << endl;
}

动规解题的一般思路

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

 把原问题分解为若干个子问题。子问题和原问题形式同样

或类似,仅仅只是规模变小了。

子问题都解决,原问题即解

决(数字三角形例)。

 子问题的解一旦求出就会被保存,所以每一个子问题仅仅需求

解一次。

2. 确定状态

 在用动态规划解题时。我们往往将和子问题相

关的各个变量的一组取值。称之为一个“状

态”。一个“状态”相应于一个或多个子问题,

所谓某个“状态”下的“值”。就是这个“状

态”所相应的子问题的解。

2. 确定状态

全部“状态”的集合,构成问题的“状态空间”。“状态

空间”的大小。与用动态规划解决这个问题的时间复杂度直接相关。

在数字三角形的样例里,一共同拥有N×(N+1)/2个数字,所以这个

问题的状态空间里一共就有N×(N+1)/2个状态。

整个问题的时间复杂度是状态数目乘以计算每一个状态所需

时间。

在数字三角形里每一个“状态”仅仅须要经过一次,且在每一个

状态上作计算所花的时间都是和N无关的常数。

2. 确定状态

用动态规划解题,常常碰到的情况是,K个整型变量能

构成一个状态(如数字三角形中的行号和列号这两个变量

构成“状态”)。

假设这K个整型变量的取值范围各自是

N1, N2, ……Nk,那么,我们就能够用一个K维的数组

array[N1] [N2]……[Nk]来存储各个状态的“值”。

这个

“值”未必就是一个整数或浮点数,可能是须要一个结构

才干表示的。那么array就能够是一个结构数组。

一个

“状态”下的“值”一般会是一个或多个子问题的解。

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

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

就是底边数字值。

4. 确定状态转移方程

定义出什么是“状态”。以及在该 “状态”下的“值”后。就要

找出不同的状态之间怎样迁移――即怎样从一个或多个“值”已知的

“状态”。求出还有一个“状态”的“值”(“人人为我”递推型)。



态的迁移能够用递推公式表示,此递推公式也可被称作“状态转移方

程”。

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

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

1) 问题具有最优子结构性质。假设问题的最优解所包括的

子问题的解也是最优的。我们就称该问题具有最优子结

构性质。

2) 无后效性。

当前的若干个状态值一旦确定。则此后过程

的演变就仅仅和这若干个状态的值有关。和之前是採取哪

种手段或经过哪条路径演变到当前的这若干个状态,没

有关系。

POJ 1163 The Triangle(经典问题教你彻底理解动归思想)的更多相关文章

  1. POJ 1163 The Triangle(简单动态规划)

    http://poj.org/problem?id=1163 The Triangle Time Limit: 1000MS   Memory Limit: 10000K Total Submissi ...

  2. poj 1163 The Triangle &amp;poj 3176 Cow Bowling (dp)

    id=1163">链接:poj 1163 题意:输入一个n层的三角形.第i层有i个数,求从第1层到第n层的全部路线中.权值之和最大的路线. 规定:第i层的某个数仅仅能连线走到第i+1层 ...

  3. OpenJudge/Poj 1163 The Triangle

    1.链接地址: http://bailian.openjudge.cn/practice/1163 http://poj.org/problem?id=1163 2.题目: 总时间限制: 1000ms ...

  4. POJ 1163 The Triangle【dp+杨辉三角加强版(递归)】

    The Triangle Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 49955   Accepted: 30177 De ...

  5. POJ 1163 The Triangle 简单DP

    看题传送门门:http://poj.org/problem?id=1163 困死了....QAQ 普通做法,从下往上,可得状态转移方程为: dp[i][j]= a[i][j] + max (dp[i+ ...

  6. poj 1163 The Triangle

    The Triangle Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 43809   Accepted: 26430 De ...

  7. 递推DP POJ 1163 The Triangle

    题目传送门 题意:找一条从顶部到底部的一条路径,往左下或右下走,使得经过的数字和最大. 分析:递推的经典题目,自底向上递推.当状态保存在a[n][j]时可省去dp数组,空间可优化. 代码1: /*** ...

  8. Poj 1163 The Triangle 之解题报告

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 42232   Accepted: 25527 Description 7 3 ...

  9. poj 1163 The Triangle 搜索 难度:0

    The Triangle Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 37931   Accepted: 22779 De ...

随机推荐

  1. (转)十步完全理解 SQL

    十步完全理解 SQL 目录[-] 10个简单步骤,完全理解SQL 1. SQL 是一种声明式语言 2. SQL 的语法并不按照语法顺序执行 3. SQL 语言的核心是对表的引用(table refer ...

  2. HDU 6251 Inkopolis(2017 CCPC-Final,I题,环套树 + 结论)

    题目链接 HDU 6251 题意 给出一个$N$个点$N$条边的无向图.然后给出$M$个操作,每个操作为$(x, y, z)$,表示把连接 $x$和$y$的边的颜色改成$z$. 求这张无向图中所有边的 ...

  3. SecureCRT导出服务器列表或配置文件

    说明:SecureCRT没有Xshell那么简单有直接导出的功能,但是可以通过技巧的方式来操作. 1.打开SecureCRT,点击菜单栏的[Opitions]->[Global Opitions ...

  4. 在delphi中,如何把十进制数转换为十六进制整形数。若用inttohex只能转化为十六进制字符串。

    var b: Byte; s: string;begin s := '31'; //16进制字符串 b := StrToInt('$' + s);end; 不过要注意一点,如果在程序调试时想看b的值, ...

  5. retain和copy还有assign的区别

    1. 接触过C,那么假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给 (assign)了b.此时a和b指向同一块内存,请问当a不再需 ...

  6. 用PHP实现弹出消息提示框

    方法一: echo "<script>alert('提示内容')</script>"; 方法二: echo '<script language=&qu ...

  7. Qt编程简介与基本知识

    1. 什么是Qt? Qt是一个基于C++的跨平台应用程序和UI开发框架.它包含一个类库,和用于跨平台开发及国际化的工具. 由挪威Trolltech公司开发,后被Nokia收购,目前被Digia公司收购 ...

  8. Injection of resource dependencies failed解决办法总结

    今天调试项目代码,出现的引resource的报错,查原因查了好长时间才找到,现在这里总结一下,以免以后忘掉以及给大家参考. 报错大致内容入下: org.springframework.beans.fa ...

  9. 2016.7.12 在navicat中用sql语句建表

    参考资料: http://jingyan.baidu.com/article/f0e83a25a8c4b022e5910116.html 即新建query,然后run. (1)点击要新建表的位置,选择 ...

  10. 解决使用maven jetty启动后无法加载修改过后的静态资源

    jetty模式是不能修改js文件的,比如你现在调试前端js,发现在myeclipse/eclipse的源码里面无法修改文件,点都不让你点,所以,你只能采用一些办法,更改jetty的模式配置. Look ...