改了两天的Dijkstra算法,最后我发现我把有向图一直当成无向图在做,多写了一行代码,结果卡了三天,耽误了太多的时间了。
Dijkstra算法,求一个顶点到另一个顶点的最短路径长度,并且保存下来路径。用标准语言来形容是:
再网图中,最短路径是指两个顶点之间经历的边权之值之和的最短路径。时间复杂度是O (n 2)
基本思想:
- 设置一个集合S存放已经找到最短路径的顶点,S的初始状态只包含源点v,
- 对vi∈V - S,假设从源点v到vi的有向边为最短路径(从v到其余顶点的最短路径的初值)。
- 以后每求得一条最短路径v, …, vk,就将vk加入集合S中,并将路径v, …, vk, vi与原来的假设相比较,取路径长度较小者为最短路径。
重复上述过程,直到集合V中全部顶点加入到集合S中。
路径长度最短的最短路径(即第一条最短路)的特点:在这条路径上,必定只含一条边,并且这条边上的权值最小。
下一条路径长度次短的最短路径的特点:它只可能有两种情况:或者是直接从源点到该点(只含一条边)。或者是从源点经过顶点v1(第一条最短路径所依附的顶点),再到达该顶点(由两条边组成)。
再下一条路径长度次短的最短路径的特点:它可能有四种情况:或者是直接从源点到该点(只含一条边); 或者从源点经过顶点v1,再到达该顶点(由两条边组成);或者是从源点经过顶点v2,再到达该顶点(两条条边);或者是从源点经过顶点v1、v2,再到达该顶点(多条边)。
其余最短路径的特点:它或者是直接从源点到该点(只含一条边); 或者是从源点经过已求得最短路径的顶点(集合S中的顶点),再到达该顶点。
尽量看懂上面的四个特点,没看懂说明没尽量。
Dijkstra基本思想
辅助数组
- dist[MaxSize]数组,是用来保存从固定一个顶点向其他所有的点连通路的最小边权。
- path[MaxSize]数组,存储路径,表示该点的下一个顶点位置。
- visited[MaxSize]数组,存储该点是否已经被访问过。
Dijkstra算法实现代码
- 第一步,为dist赋初值,为第一个顶点与之相连接边的权值,不连通则赋值无穷大。访问数组全部赋值0,都没有被访问。path数组初值-1 。
- 循环n-1次,找到n-1条路径。每次循环的内容是:找到dist中最短的那条边,然后记录位置,使这个位置成为这一次循环确定的最短通路。
- 然后把这条边加入到已经确定的通路集合里,遍历其他所有的顶点,进行松弛操作,若新点与之连接比之前连接的顶点短,则更新dist数组。
- 最后的输出利用的栈,因为想要使从开头走向结尾,如果想要反向,则去掉栈就可以。
#include<iostream>
#include<stack>
using namespace std;
const int MaxSize = 20;
const int INF = 9999;
int dis[MaxSize];
int visited[MaxSize];
int path[MaxSize];
class MGraph
{
int arcNum;
int vertexNum;
int arc[MaxSize][MaxSize];
public:
MGraph(int n, int e)
{
arcNum = e;
vertexNum = n;
for (int i = 0; i < vertexNum; ++i)
{
for (int j = 0; j < vertexNum; ++j)
{
if (i == j)
arc[i][j] = 0;
else
arc[i][j] = INF;
}
}
for (int i = 0; i < arcNum; ++i)
{
int a, b, v;
cin >> a >> b >> v;
arc[a][b] = v;
}
}
void Dijkstra(int v)
{
for (int i = 0; i < vertexNum; ++i)
{
dis[i] = arc[v][i];
visited[i] = 0;
path[i] = -1;
}
visited[v] = 1;
for (int i = 0; i < vertexNum; ++i)
{
int min = INF;
int k = 0;
for (int j = 0; j < vertexNum; ++j)
{
if (min > dis[j] && visited[j] == 0)
{
min = dis[j];
k = j;
}
}
visited[k] = 1;
for (int j = 0; j < vertexNum; ++j)
{
if (visited[j] == 0 && dis[j] > dis[k] + arc[k][j])
{
dis[j] = dis[k] + arc[k][j];
path[j] = k;
}
}
}
}
};
int main()
{
int x, y;
cin >> x >> y;
int s, e;
cin >> s >> e;
MGraph G(x, y);
G.Dijkstra(s);
if (dis[e] == INF)
cout << "no answer" << endl;
else
{
cout << dis[e] << endl;
cout << "v" << s << " ";
int p = e;
stack<int>st;
while (path[p] != -1)
{
st.push(path[p]);
p = path[p];
}
while (!st.empty())
{
cout << "v" << st.top() << " ";
st.pop();
}
cout << "v" << e;
}
return 0;
}