数据结构与算法(7)动态规划法

动态规划法(dynamicprogramming)也是将待求解问题分解成若干个子问题,但是子问题之间往往不是相互独立的,
如果用分治法求解,这些子问题的重叠部分被重复计算多次。

动态规划法将每个子问题求解一次并将其解保存在一个表格(通常采用数组)中,当需要再次解此子问题时,只是简单地通过查表获得该子问题的解,从而避免了大量重复计算。

动态规划法的一般过程:
在这里插入图片描述

一般来说,动态规划法的求解过程由以下三个阶段组成。
(1)划分子问题:将原问题分解为若干个子问题,并且子问题之间具有重叠关系;
(2)动态规划函数:根据子问题之间的重叠关系找到子问题满足的递推关系式(称为动态规划函数);
(3)填写表格:设计表格的形式及内容,根据递推式自底向上计算,实现动态规划过程。

算法设计实例——数塔问题

【问题】 如图2-8所示的一个数塔,从数塔的顶层出发,在每一个结点可以选择向左走或向右走,一直走到底层,要求找出一条路径,使得路径上的数值和最大。
例如,所示数塔的最大数值和是:8+15+9+10+18=60。
在这里插入图片描述

从5层数塔的顶层(设顶层为第1层)出发,下一层选择向左走还是向右走取决于两个4层数塔的最大数值和

在这里插入图片描述

如何找到子问题满足的动态规划函数呢?
显然,动态规划的求解需要从底层开始进行决策。
底层的每个数字可以看做1层数塔,则最大数值和就是其自身;
第4层的决策是在最底层决策的基础上进行求解的,可以看做4个2层数塔,对每个数塔进行求解;
第3层的决策是在第4层决策的基础上进行求解的,可以看做3个2层的数塔,对每个数塔进行求解,
最后第1层的决策结果就是数塔问题的整体最优解。

在这里插入图片描述

在这里插入图片描述

【程序】 主函数首先初始化数组d[n][n]为n层数塔的数字,然后调用函数DataTorwer求解最大数值和并输出相应的路径。程序如下:

#include <stdio.h>

const int n = 5;		// 设塔是5层
int DataTorwer(int d[n][n]);		// 函数声明,求解n层数塔 

int main(void)
{
	int d[n][n]={{8}, {12,15}, {3,9,6}, {8,10,5,12}, {16,4,18,10,9}};
	printf("最大数值和为: %d\n", DataTorwer(d));
	return 0;
}
int DataTorwer(int d[n][n])
{
	int maxAdd[n][n]={0}, path[n][n]={0};
	int i, j;
	
	for( j=0; j<n; j++)
		maxAdd[n-1][j] = d[n-1][j];  //  ====> maxAdd[4][] = {16, 4, 18, 10, 9};
		
	for(i=n-2;  i>=0; i--)			// i =  3  2  1  0
	{
		for( j=0; j<=i; j++)
		{
			if( maxAdd[i+1][j] > maxAdd[i+1][j+1])
			{
				maxAdd[i][j] = d[i][j] + maxAdd[i+1][j];
				path[i][j] = j;
			}else{
				maxAdd[i][j] = d[i][j] + maxAdd[i+1][j+1];
				path[i][j] = j+1;
			}
		}
	}
	printf("路径为:%d ",d[0][0]);
	j = path[0][0];
	for( i = 1; i< n; i++)
	{
		printf(" --> %d ", d[i][j]);
		j = path[i][j];
	}
	
	return maxAdd[0][0];
}

在这里插入图片描述

发布了349 篇原创文章 · 获赞 74 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/Ciellee/article/details/105135036