1.数字三角形及动态规划

问题描述
  (图3.1-1)示出了一个数字三角形。 请编一个程序计算从顶至底的某处的一条路
  径,使该路径所经过的数字的总和最大。
  ●每一步可沿左斜线向下或右斜线向下走;
  ●1<三角形行数≤100;
  ●三角形中的数字为整数0,1,…99;


  .
  (图3.1-1)
输入格式
  文件中首先读到的是三角形的行数。

  接下来描述整个三角形
输出格式
  最大总和(整数)
样例输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出
30


分析:

我的第一反应是利用深度优先遍历穷举出所有路径的值并进行比较

开始确实行之有效,但是随着行数的增加,不可避免地运行超时了

试着化简,还是无效。

后来查找答案,才知道还有一种叫做动态规划的方法,

把问题拆成许多步,求出每一步的最优解,直到求该问题的最优解

每个步的最优解是从它前面步骤最优解里面选出的


比如这个问题,求第1层到第n层的数字总和最大

我们可以拆成如下若干问题:

1、第n层到第n-1层最大值;

2、在1的基础上,第n-1层到第n-2层最大值;

3、在2的基础上,第n-2层到第n-3层最大值

...

n、在前面问题的基础上,求第2层到第一层的最大值


由于题目对三角形路径有限定

即第n层的第i号只能走到第n+1层的第i,i+1号上(i+1<n+1)

所以每一步若干个最优解,进行下一步时,从这些最优解里面选出,求得下一步若干个最优解



说了这么多,以题目例子来试一试:

三角形:                    

第1层             7
第2层           3 8
第3层          8 1 0
第4层        2 7 4 4

第5层       4 5 2 6 5


我们可以分成4步

(1)第5层返回第4层:怎么样相加才能最大呢?

当然是i与他左右孩子里面最大的一个相加啊!

比如第4层的2,左孩子为第5层的4,右孩子为第5层的5,肯定与有孩子相加啊

结果为2+5=7;

同理,7与右孩子(5)相加=12,4与右孩子(6)相加=10,4与左孩子(6)相加=10

加完一遍后,第4层从2 7 4 4 变成了 7 12 10 10

本步骤的最优解即7 12 10 10


(2)第4层返回第3层:因为(1),得:

第3层:   8   1   0

第4层:7   12   10  10   

同理(1),第二层的最优解为:20 13  10


(3)第3层返回第2层

第2层    3   8

第3层  20 13 10

最优解:23  21


(4)第2层返回第1层(最终问题)

第1层    7

第2层 23  21

最优解(最终答案):30


经过这么一分析,我也得到了动态转移方程:

a[i-1][j] = a[i][j] + max( a[i][j] , a[i][j+1] );(j+1<i)

#include <stdio.h>

int a[105][105];
int num;

void dp(int n){
	for(int i=n-1;i>0;--i){
		for(int j=0;j<n-1;++j){
			if(a[i][j]>a[i][j+1]){
				a[i-1][j]=a[i][j]+a[i-1][j];
			}else{
				a[i-1][j]=a[i][j+1]+a[i-1][j];
			}
		}
	}
}//动态规划 

int main(){
	int k;
	scanf("%d",&num);
	int i,j;
	for(i=0;i<num;++i){
		for(j=0;j<i+1;++j){
			scanf("%d",&a[i][j]);
		}
	}
	dp(num);
	printf("%d",a[0][0]);
	return 0;
}



猜你喜欢

转载自blog.csdn.net/qq_40636117/article/details/80939789