首先要明白这个算法的原理:
如图:找v0到v6的最短路径。
在找最短路之前先画一个表格:vj代表这一轮选出的最短路径,距离就是最短距离。
无法到达用INF(无穷)表示
具体寻找步骤:
i=1:v1 = 13 , v2 = 8 , v3 = INF , v4 = 30 , v5 = INF , V6 = 32 这一轮选出的最短距离为v2 = 8。
i=2: 既然v2是最短路那么从v2走到的点(可能更短)也被记录(每轮选出的最短路都可用)
注意这里v2已被选出是最短路则不更新。
v1 = 13 , v3 = (8 + 5)(通过v2的点) , v4 = 30 , v5 = INF , V6 = 32
注意 : 如果某点可以通过多个点到达,选择最短的一条。
最终表格
算法总结
1.初始化:先找出从v0到到各点的直达路径(通过一条弧到达的路径)。
2.选择:从这些路径找出最短的路径。
3.更新:通过找到的最短路能否更新其他路。
选择代码实现
// dis表示到起点路径
for (int j = 1; j <= n; j++)
{
if (dis[j] < dis[t]) t = j; // 遍历整个路径选出最短路的点t
}
更新代码实现
//g[t][j]表示t到j的路径大小
for (int j = 1; j <= n; j++)
{
dis[j] = min(dis[j], dis[t] + g[t][j]); //通过找到的最短路能否更新其他路
}
Dijkstra求最短路代码
void dijkstra()
{
memset(dis, 0x3f, sizeof dis); // 初始化距离为无穷
dis[1] = 0; // 初始化为了找出从起点到各点的直达路径
for (int i = 0; i < n; i++)
{
int t = 0; // 保证t每次都被更新dis[t] = 无穷
for (int j = 1; j <= n; j++)
{
if (!vis[j] && dis[j] < dis[t]) t = j; // 遍历整个路径选出最短路
}
vis[t] = true; // 该点已是最短路,不在更新
for (int j = 1; j <= n; j++)
{
dis[j] = min(dis[j], dis[t] + g[t][j]); //通过找到的最短路能否更新其他路
}
}
}
堆优化
思路
思路与上面一样,只不过选择是用堆来实现。
1.初始化
2.选择:将被更新的路入队比较,选择队中的最短路(小根堆的堆顶)。
3.更新:通过找到的最短路能否更新其他路,将更新后的路径入队来取代堆中原来该路的路径。
(堆不能删除,但可以比较,更新后会在原路径上面,达到了取而代之的作用)。
int dijkstra()
{
priority_queue<PII, vector<PII>, greater<PII>> heap; // 定义小根堆
memset(dis, 0x3f, sizeof dis); // 初始化距离为无穷
heap.push({ 0,1 }); // 从1结点开始做初化
// 堆存结点和该结点到1的距离
// 堆是先按第一个数排序,所以第一存距离
// pair<结点到1的距离 ,结点>
while (heap.size())
{
auto t = heap.top(); heap.pop(); // 队头一定是最短路经
int d = t.first, v = t.second;
if (vis[v]) continue; // 防止重边情况
vis[v] = true; // 第一次一定是该点最短路
for (int i = h[v]; i != -1; i = ne[i])
{
int j = e[i];
if (dis[j] > d + w[i]) //通过找到的最短路能否更新其他路
{
dis[j] = d + w[i]; // 更新到j的最短路
heap.push({ dis[j], j }); // 将该条路入队
}
}
}
}