知识常看常新,虽然之前在刷pat时也重新复习过迪杰斯特拉算法,但是当时的注意力主要还是集中在对题目的解决上,而不是对这个算法本身的理解上,所有我想重新写一篇文章,来记录这个算法。
迪杰斯特拉算法主要依靠的是贪心算法和BFS求最短路径,需要维护的数组共有四个,dist[]数组,pre[]数组,s[]数组和st[]数组。dist[]数组维护的是点v0到之后各点的最短路径长度;pre[]数组维护的是各节点的前驱节点,用来求到各点的最短路径,求最短路径需要使用回溯;s[]数组是目前已知节点的集合,探索到的顶点设置为true,没探索到到的顶点设置为false;st[]数组是顶点的全集减去s集合,所剩下的待探索的元素。
操作步骤如下:
(1) 初始时,s[]只包含起点v0;st[]包含除v0外的其他顶点,dist[0]设置为0,dist[i]=graph[0][i],也就是把dist数组初始化为距离矩阵中的点v0到该点的距离。
(2) 从st数组中选出dist值最小的顶点k,并将该顶点k加入到s数组中,同时,从st数组中移除顶点k。
(3) 更新dist中各个顶点到起点v0的距离。之所以更新dist中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(v0,v)的距离可能大于(v0,k)+(k,v)的距离。
(4) 重复步骤(2)和(3)一共n-1次,因为每循环一次就从st数组中取一个元素加入s数组,一共需要n-1次st数组才为空,此时遍历完所有顶点。
代码如下:
#include<iostream>
#include<vector>
using namespace std;
void InputGraph(vector<vector<int>> &graph) //输入顶点之间的权值,否则为无限大
{
int count = 0;
cin >> count;
for (int i = 0; i < count; i++)
{
int start = 0, end = 0,weight=0;
cin >> start >> end>>weight;
graph[start][end]= weight;
}
}
void Dijkstra(vector<vector<int>> &graph,vector<int> &dist,vector<int> &pre)//计算最短路径
{
int size = graph.size();
dist=vector<int>(size);
pre=vector<int> (size);
vector<bool> s(size);
vector<bool> ts(size);
dist[0] = 0;
pre[0] = -1;
s[0] = true;
ts[0] = false;
for (int i = 1; i < size; i++) //初始化数组
{
dist[i] = graph[0][i];
s[i] = false;
ts[i] = true;
}
for (int i = 0; i < size - 1; i++) //共n-1次循环
{
int index = -1;
int min = 999999;
for (int i = 1; i < size; i++)
{
if (ts[i] == true && min >= dist[i])
{
index = i;
min = dist[i];
}
}
ts[index] = false;
s[index] = true;
for (int i = 1; i < size; i++)
{
if (dist[index] + graph[index][i] < dist[i])
{
dist[i] = dist[index] + graph[index][i];
pre[i] = index;
}
}
}
cout << "结果如下所示:" << endl;
for (int i = 1; i < size; i++)
{
cout << dist[i] << endl;
}
cout << endl;
for (int i = 1; i < size; i++)
{
cout << pre[i] << endl;
}
}
void getRoute(vector<int> &pre,int v) //递归得到最短路径
{
if (pre[v] == -1)
{
cout << 0;
return;
}
else
{
getRoute(pre,pre[v]);
cout << "->" << v ;
}
}
int main()
{
vector<vector<int>> input =vector<vector<int>>(5,vector<int>(5,999999));
vector<int> dist;
vector<int> pre;
InputGraph(input);
Dijkstra(input, dist, pre);
for (int i = 1; i < 5; i++)
{
getRoute(pre, i);
cout << " dist=" << dist[i] << endl;
}
system("pause");
return 0;
}