【算法概论】动态规划:最短路径问题


因为刚开始想着,既然在图中表示,就要用到图的存储结构等等吧,所以 ?

首先,要复习一下图的相关知识(学完数据结构后过了不长的时间,已经还给老师了?)

1、图的存储结构:

       邻接矩阵表示法 和 邻接表表示法(详见 图 - 邻接表表示法)。

2、图的基本算法:

       计算图的顶点数量,计算图的边数量,返回第i个顶点的值,插入一个顶点,删除一个顶点,插入一条边,删除一条边,深度优先遍历图,广度优先遍历图。

       拓扑排序


接着,来看下面这道多段图中的最短路径问题(The shortest path in multistage graphs)

问题描述:

       建立一个从源点S到终点T的多段图,设计一个动态规划算法求出从S到T的最短路径值,并输出相应的最短路径。 

解决思路(老师讲课):

       首先,暴力法是遍历从 S 到 T 的所有路径,依次比较。

       但我们可以使用更优的方法 —— 动态规划。

       很容易看出,这是一个多阶段决策的问题,S —— A、B、C —— D、E、F —— T 分别是四个阶段,如下图所示:

       按照 自底向上(bottom-up) 的方法,d(S, T) = min{ 1 + d(A, T), 2 + d(B, T), 5 + d(C, T) };这满足 动态规划 的 最优子结构 的性质,即,问题的最优解包含其子问题的最优解。

算法实现(老师讲课):

/*伪代码*/
d[1] = 0

for j = 2 to n:
    for all <i,j> ∈E :
        d[j] = min{ d[i] + w [i,j] }

return d[n]

有向无环图中的最短路径问题(The shortest path in dags):

问题描述:

       建立一个从源点S到终点E的有向无环图,设计一个动态规划算法求出从S到E的最短路径值,并输出相应的最短路径。

解决思路(老师讲课):

       有向无环图不像多段图,有明确的分阶段,它能转换成多段图进行求解吗?

       也可以,因为,有向无环图 可以通过 拓扑排序 将其转换为 线性结构。

       Notice that, the special distinguishing feature of a dag is that its nodes can be linearized; that is, they can be arranged on a line so that all edges go from left to right. 如下图所示:

        (回到了这篇文章开头的地方)。

算法实现:

       从图中可以看出:

/*伪代码*/
initialize all dist(.) values to
    dist(s) = 0
for each v V\{s}, in linearized order;
    dist(v)=min {dist(u) + (u,v)}

       所以我本来想着要用着邻接表啊一些数据结构的知识,便复习了一番,最终代码太繁琐,在deadline之前调不完了……

……so,先暂空着……

 

However,

       在网上查找相关代码的时候,发现了如下的代码,自己又改了一部分:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	cout << "请输入图的顶点数目:" << endl;
	int vexnum;
	cin >> vexnum;
	vector<int> cost(vexnum, 0);			//cost[i]表示从顶点i到终点n-1的最短路径长度
	vector<int> path(vexnum, 0);			//path[i]表示从顶点i到终点n-1的路径上顶点i的下一个顶点

	cout << "请输入图的边数:" << endl;
	int edgenum;
	cin >> edgenum;

	vector<vector<int>> edge(vexnum, vector<int>(vexnum, 0));			//edge[i][j]存储多段图中的边

	cout << "请依次输入图中各边的起点终点和路径长度:" << endl;
	int start;
	int end;
	int length;
	for (int i = 0; i < edgenum; ++i)
	{
		cin >> start >> end >> length;
		edge[start][end] = length;
	}

	for (int i = vexnum-2; i >= 0; --i)
	{
		cost[i] = INT_MAX;
		for (int j = i; j < vexnum; ++j)
		{
			if (edge[i][j] != 0)
			{
				//等于零表示之间没有路
				if (edge[i][j] + cost[j] < cost[i])
				{	
					//此时找到一条更短的路
					path[i] = j;						//更新path[i]
					cost[i] = edge[i][j] + cost[j];		//更新从该节点出发的最短路径
				}
			}
		}
	}
	cout << "最短路径长度是:" << cost[0] << endl;
	cout << "最短路径为:" << endl;
	int i = 0;
	cout << "0 ---> ";
	while (1)
	{
		cout << path[i];
		i = path[i];
		if (i == vexnum-1)
		{
			break;
		}
		cout << " ---> ";
	}
	cout << endl;

	return 0;
}

       其实,这种代码,适用于上述两种最短路径的情况,只要确定了各顶点的序号,输入就OK啦!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值