课程来自:https://class.coursera.org/cplusplus4c-002/lecture
这节课讲述的是Dijkstra最短路径算法的具体实现。
Dijkstra最短路径算法是贪心算法的一个实例,给定一个权值不为负的图,出发点s以及目的点t,要求s到t的最短路径。
核心步骤是:每次都选取离s最近的且没有被关闭的点将其关闭。
数组约定: dist[i]表示i号点到s点的最短距离,prev[i]表示i号点的前驱点,closed[i]为true表示i号点已被关闭
起始状态:设定关闭点集合closed[ ],利用图给数据初始化所有与s直接相连的点i距离dist[ ],并将它们的先驱点prev[ ]设为s,将s关闭
循环步骤:A. 遍历所有没关闭的点,求出其中dist最小的那个,设为它的后继点ssr,将ssr关闭(ssr为t时停止循环)
B. 遍历所有没关闭的点,如果(它的dist)小于(ssr的dist加上从ssr到它的距离),说明ssr的加入导致它的dist减小,更新它的dist,并将其prev改为ssr
结束步骤:最小距离为dist[t],建立一个栈按prev输出路径.
最短路径有最优子结构性质,假设最后得到的路径最短,那么它的每个子路径也是最短,因为如果不是这样就存在更好的子结构,将这个子结构替换成那个更好的子结构后这个路径总体还会更优,这就产生矛盾了。(这个性质说明贪心算法非常适合解决这个问题)
#include <cstdio>
#include <iostream>
#include <stack>
using namespace std;
const int MAX = 0x3f3f3f3f;
const int NUM = 7;
int Dijkstra(int Graph[][NUM], int s, int t)
{
int dist[NUM], prev[NUM];
bool closed[NUM];
for (int i = 1; i < NUM; ++i)
{
if (i == s)
{
dist[i] = 0;
closed[i] = true;
prev[i] = i;
}
else
{
dist[i] = Graph[s][i];
closed[i] = false;
if (Graph[s][i]<MAX)
prev[i] = s;
}
}
do
{
int ssr;
int mindist = MAX;
for (int i = 1; i < NUM; i++)
{
if (!closed[i] && mindist>dist[i])
{
ssr = i;
mindist = dist[i];
}
}
closed[ssr] = true;
for (int i = 1; i < NUM; i++)
{
if (!closed[i] && dist[i]>dist[ssr] + Graph[ssr][i])
{
dist[i] = dist[ssr] + Graph[ssr][i];
prev[i] = ssr;
}
}
} while (!closed[t]);
stack<int> output;
int p = t;
for (;;)
{
output.push(p);
p = prev[p];
if (p == s)
{
output.push(p);
break;
}
}
int k = output.size();
for (int i = 0; i < k - 1; ++i)
{
printf("%d -> ", output.top());
output.pop();
}
printf("%d\n", t);
return dist[t];
}
int main()
{
int Graph[NUM][NUM] = {
0,0,0,0,0,0,0,
0,0,4,3,2,MAX,MAX,
0,4,0,4,MAX,2,MAX,
0,3,4,0,6,5,3,
0,2,MAX,6,0,MAX,12,
0,MAX,2,5,MAX,0,8,
0,MAX,MAX,3,12,8,0
};
int dist = Dijkstra(Graph, 1, 6);
printf("The minimum distance is %d.\n", dist);
return 0;
}