数据结构与算法(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];
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

"小夜猫&小懒虫&小财迷"的男人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值