欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

动态规划-数字三角形

程序员文章站 2024-02-21 18:51:10
...

数字三角形

问题

  • 求自顶向下的最大路径之和,只能往左下和右下走,三角形行数最大为100。
    动态规划-数字三角形

输入格式

  • 怎么用数组存储三角形的数据,使用二维数组A
    5 // A[0][0]三角形的行数
    7
    3 8
    8 1 0
    2 7 4 4
    4 5 2 6 5

解题思路

  • D(i,j):第i行第j列(i,j从1开始算起)。这是一个二维数组用来存储三角形数据。
  • MaxSum(i,j):从D(i,j)到底边的各条路径中最大的路径和,可能不唯一。
  • D(i,j)出发,下一步只能走D(i+1,j) or D(i+1,j+1)
  • 所以只需以下步骤
if(r == N)
	MaxSum(i,j) = D(i,j)
else
	MaxSum(i,j) = Max{ MaxSum(i+1,j), MaxSum(i+1,j+1) } + D(i,j)
	// D(i,j)是一个具体的数,从他下面求最大路径+自己的值=他到底边最大路径

递归的伪代码表示

  • 此法不可行,时间复杂度为2^n,发生了子问题的重复求解。
int D[MAX][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++)	//三角形列数=行数,第一行1个,第二行2个,第n行n个
			cin >> D[i][j]	//给数字三角形赋值
	cout << MaxSum(1,1)	//即求自顶向下的最大路径
}

动态规划-数字三角形

  • 如图,1的次数=3的时候计算1次,8的时候计算1次
  • 7的次数=8的时候计算1次,1的时候计算2次

备忘录法(自顶向下:需要递归)

  • 只要把每次计算的值存储起来MaxSum(i , j)就不用重复计算了,计算之前先判断此值有没有被计算过即可。
  • 由于只要计算n行个数,1+2+3+…+n = n(n+1)/2,所以时间复杂度是O(n^2)。
#define MAX 101;	//MAX:三角形行的最大值,预先定义
int D[MAX][MAX];	
int maxSum[MAX][MAX];	//用来保存计算过的数
int n;	//三角形的行数,用户输入
int MaxSum(int i, int j){
	if (maxSum[i][j] != -1)	
        //判断是否计算过,例如判断第3行是否被计算过,如果是,直接返回第3行的最大值
        //如果没有,就计算第二行的最大值+第3行的数。再判断第2行有没有计算过
        //假如有,则返回该行最大值参与(本块17行)的计算。以此类推
		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++)	//三角形列数=行数,第一行1个,第二行2个,第n行n个
			cin >> D[i][j]	//给数字三角形赋值
			maxSum[i][j] = -1	
			//赋初值-1,因为从D(i,j)到底边的最大路径为正数,-1表示没有被计算过
	cout << MaxSum(1,1)	//即求自顶向下的最大路径
}

递推法(自底向上:不用递归)

动态规划-数字三角形

  • 以此法填完表格,如下图。所以可以使用2层循环语句替换递归表达式。

动态规划-数字三角形

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)	//从倒数第2行开始往上
		for(int j = 1; j<=i; ++j)	//第几行就有几个数
			maxSum[i][j]=max(maxSum[i+1][j], maxSum[i+1][j+1]) + D[i][j]
			//此时的i是倒数第2行的数,所以倒数第2行+下面一行最大值=该数最大值
	cout << maxSum[1][1]
}

递推法的空间优化

动态规划-数字三角形