动态规划之五:数字三角形

问题:将一个由n行数字组成的三角形,如图所示,设计一个算法,计算出三角形的由顶至底的一条路径,使该路径经过的数字总和最大?


图1数字三角形


       首先拿到这题,我们第一想法肯定是使用深度优先算法DFS或者广度优先算法BFS,但是使用DFS算法需要遍历所有点,搜索时会重复遍历一些点,导致时间成指数增长。


图2重复计算的次数

设我们用二维数组map[m][n]来存储数字三角形,把图1转换成实际的存储格式:


图3数字三角形存储格式

如图2和图3所示,我们通过观察可以发现,三角形的边界位置如3、8、2 、4等的位置只需要计算一次,而中间的位置数字例如1的计算次数为上一行3的次数加上8的次数,则次数计算公式为:

                                            map[i][j]=map[i-1][j-1]+map[i-1][j]  ( i>0&&i<=m,j>0&&j<=n     )


      map[i][j]来表示第i行第j个数字( i和j都是从1开始),现在来使用DFS分析可以发现,从map[i][j]出发,我们可以选择的下一条路径只有map[i+1][j]或者map[i+1][j+1],因此递推公式可以描述为

                                  max(i,j)=max ( max(i+1,j) , max(i+1,i+1) ) +map[i][j]

  

                                                                                  图4递归遍历方式

程序结果:

#include <iostream>    
 
#define MAX 10    
using namespace std;
int map[MAX][MAX];
int n;
int Max(int i, int j) {
	if (i == n)
		return map[i][j];
	int x = Max(i + 1, j);
	int y = Max(i + 1, j + 1);
	return (x>y?x:y) + map[i][j];
}
int main() {
	int i, j;
	cin >> n;
	for (i = 1; i <= n; i++)
		for (j = 1; j <= i; j++)
			cin >> map[i][j];
	cout << Max(1, 1) << endl;
	system("pause");
}

虽然使用递归可以解决问题,但是效率不高,想要提高效率就需要数字三角形中的每个数字只需要计算一遍即可,我们使用f[i][j]来保存表示从顶点(1, 1)到顶点(i, j)的最大值。

通过对上面的递归地分析可得状态转移函数为:

            f[i][j]=max(f[i+1][j],f[i+1][j+1])+map[i][j]

程序结果如下:

#include<iostream>

#define size 20
using namespace std;

int main() {
	int map[size][size];
	int  n;
	cin  >> n;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= i; j++)
			cin >> map[i][j];
		
	for (int i = n - 1; i > 0; i--)
		for (int j = 1; j <= i; j++)
			map[i][j] += (map[i + 1][j] > map[i + 1][j + 1] ? map[i + 1][j] : map[i + 1][j + 1]) ;

	cout << map[1][1] << endl;
	system("pause");
	return 0;
}




阅读更多
个人分类: 动态规划
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭