动态规划入门-----数塔问题(求路径及路径最大值)

(思考)我们知道贪婪算法也是进行多阶段的决策过程,通过一系列的贪婪决策找到最优解.那么动态规划和贪婪算法的区别在哪里?

如果不太清楚,我们从今天这个列子来体会.

数塔问题:

数塔从顶部出发,在每一个节点可以选择向左走或是向右走,一直走到底层,要去找出一条路径,
使路径上的数值和最大.
            9
        12  15
     10   6    8
   2    18    9    5

19    7   10   4   16

算法策略:
这个问题不能用贪婪法来解决,为什么呢?
因为贪婪策略每次无论是向上而下,还是自下而上,每次向下都选择较大的一个数移动.
但是由于我们采用贪婪策略,无法得到数塔的全貌只是在一层做贪婪选择,这样可能会得到不正确的答案,所以不采用.


若采用枚举算法?
在数塔的层数为n时,要枚举的路径为2^n-1,数目非常之大,所以也不采用.


分而治之的算法呢?
这个问题的原始数据是一个三角形的二维图形,而且问题的答案与各层数据间关系复杂,所以不适合采用分治法.

所以采用动态规划.

分析一下动态规划的过程:

1)数据结构采用:
原始数据采用二维数组来模拟数塔.
2)动态规划的过程存储:
如果仅仅是求最优解,那么采用一维数组存储最新的决策过程即可,但是这块要求经过的路径,那么采用另一个二维数组存储最新决策.
3)最优解路径求解及存储
原始数据data:                                最优解求解策略数组d(由底向上)
9                                        59
12   15                                    50        49
10    6    8                                38        34        29
2    18    9    5                            21        28        19        21
19    7    10   4   16                    19        7        10        4        16
计算路径的过程:
    1.输出data[0][0]=9
    2.d[0][0]-data[0][0]=50     对应d[1][0]----->输出data[1][0]=12
    3.d[1][0]-data[1][0]=38     对应d[2][0]----->输出data[2][0]=10
    4.d[2][0]-data[2][0]=28     对应d[3][1]----->输出data[3][1]=18
    5.d[3][1]-data[3][1]=10     对应d[4][3]----->输出data[4][3]=10

过程想清楚之后也就好写代码了.

代码实现:(以题目中的五层为列)

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;



int getmax(int a, int b)
{
	return (a > b) ? a : b;
}
vector<int> GetMaxroad(int data[10][10],int maxlayer, int *max)
{
	vector<int> v;
	int i, j;
	int d[10][10];
	//初始化数组d
	for (i = 0; i < maxlayer; ++i)
	{
		for (j = 0; j <= i; ++j)
		{
			d[i][j] = data[i][j];
		}
	}
	//进行动态规划,计算出最优解
	for (i = maxlayer - 2; i >= 0;--i)
	{
		for (j = 0; j <= i; ++j)
		{
			d[i][j] += getmax(d[i+1][j],d[i+1][j+1]);
		}
	}
	*max = d[0][0];

	int max1 = d[0][0];
	//根据最优解的策略,计算出最优路径
	for (i = 0; i < maxlayer; ++i)
	{
		for (j = 0; j <= i; ++j)
		{
			if (max1 == d[i][j])
			{
				v.push_back(data[i][j]);
				max1 = max1 - data[i][j];
				continue;
			}
		}
	}
	return v;
}

int main()
{
	int data[10][10];//用二维数组模拟数塔
	vector<int> result;//得到路径
	int max=0;
	int n;//层数
	cin >> n;
	//初始化数塔
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j <= i; ++j)
		{
			cin >> data[i][j];
		}
	}
	result = GetMaxroad(data,n,&max);
	cout << "最优解是" << max << endl;
	cout << "路径为:";
	for (int i = 0; i < result.size(); ++i)
	{
		cout << result[i]<<" ";
	}
	cout << endl;
	return 0;
}

现在应该可以稍微体会到了动态规划和贪婪算法的区别了.

我来回答这个问题:

贪婪算法的效率比较高,每次作出的决策都是局部的,唯一的.且贪婪算法是在"线性的解决问题",所以贪婪算法适用问题的范围小.

而动态规划的每个阶段的决策,作出的是一组局部的决策结果,每一个阶段都使问题规模变小,且更加接近最优解,直到最后一步,问题的规模变为1,就找到了问题的解.所以动态规划是全面分阶段的解决问题.

发布了40 篇原创文章 · 获赞 23 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/suoyudong/article/details/89298229