基本原理
Dijkstra算法是根据贪心算法实现的,首先找出当前点到所有能到达的点之间最短的距离,然后松弛一次继续循环。所谓松弛一次,就是在已经访问过的点中遍历一遍,看看有没有更近的,如果有更近的就更新距离。这样每次找最近的可达点+松弛遍历历史节点的操作,一直重复就能找到最短路径。
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。
它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。
算法步骤
- 指定起始点s。
- 找到起始点相邻的点开始记录
- 将第二步记录的点作为起始点,如果第二部记录了多个点的话,那么按照与起始点s的距离或者权值,其中权值最小的优先依次作为起始点。
- 直到遍历完图中所有的点。
过程图解
初始配置表
v | Known | dv | pv |
---|---|---|---|
v1 | 0 | 0 | 0 |
v2 | 0 | ∞ | 0 |
v3 | 0 | ∞ | 0 |
v4 | 0 | ∞ | 0 |
v5 | 0 | ∞ | 0 |
v6 | 0 | ∞ | 0 |
v7 | 0 | ∞ | 0 |
在v1被声明为已知后的表
v | Known | dv | pv |
---|---|---|---|
v1 | 1 | 0 | 0 |
v2 | 0 | 2 | v1 |
v3 | 0 | ∞ | 0 |
v4 | 0 | 1 | v1 |
v5 | 0 | ∞ | 0 |
v6 | 0 | ∞ | 0 |
v7 | 0 | ∞ | 0 |
在v4被声明为已知后的表
v | Known | dv | pv |
---|---|---|---|
v1 | 1 | 0 | 0 |
v2 | 0 | 2 | v1 |
v3 | 0 | 3 | v4 |
v4 | 1 | 1 | v1 |
v5 | 0 | 3 | v4 |
v6 | 0 | 9 | v4 |
v7 | 0 | 5 | v4 |
在v2被声明为已知后的表
v | Known | dv | pv |
---|---|---|---|
v1 | 1 | 0 | 0 |
v2 | 1 | 2 | v1 |
v3 | 0 | 3 | v4 |
v4 | 1 | 1 | v1 |
v5 | 0 | 3 | v4 |
v6 | 0 | 9 | v4 |
v7 | 0 | 5 | v4 |
在v5然后v3被声明为已知后的表
v | Known | dv | pv |
---|---|---|---|
v1 | 1 | 0 | 0 |
v2 | 1 | 2 | v1 |
v3 | 1 | 3 | v4 |
v4 | 1 | 1 | v1 |
v5 | 1 | 3 | v4 |
v6 | 0 | 8 | v3 |
v7 | 0 | 5 | v4 |
在v7被声明为已知后的表
v | Known | dv | pv |
---|---|---|---|
v1 | 1 | 0 | 0 |
v2 | 1 | 2 | v1 |
v3 | 1 | 3 | v4 |
v4 | 1 | 1 | v1 |
v5 | 1 | 3 | v4 |
v6 | 0 | 6 | v7 |
v7 | 1 | 5 | v4 |
在v6被声明为已知后的表
v | Known | dv | pv |
---|---|---|---|
v1 | 1 | 0 | 0 |
v2 | 1 | 2 | v1 |
v3 | 1 | 3 | v4 |
v4 | 1 | 1 | v1 |
v5 | 1 | 3 | v4 |
v6 | 1 | 6 | v7 |
v7 | 1 | 5 | v4 |
至此我们可以得出从v1出发到所有点的最短路径
伪代码
Dijkstar算法的声明
typeof int Vertex;
struct TableEntry
{
List Header; /*Adjacency list*/
int Known;
DistType Dist;
Vertex Path;
}
/*Vertices are numbered from 0*/
#define NotAVertex(-1)
typeof struct TableEntry Table[NumVertex];
表初始化例程
void InitTable(Vertex Start, Graph G, Table T)
{
int i;
ReadGraph(G,T);
for(i=0; i<NumVertex; i++)
{
T[i].Known = false;
T[i].Dist = Infinity;
T[i].Path = NotVertex;
}
T[Start].dist = 0;
}
显示实际最短路径的例程
void PrintPath(Vertex V, Table T)
{
if(T[V].Path != NotVertex)
{
PrintPath(T[V].Path,T);
prithf("to");
}
printf("%v",V) /*%v is pseudocode*/
}
Dijkstra算法
void Dijkstra(Table T)
{
Vertex V, W;
for(; ;)
{
V = smallest unkonwn diatance vertex;
if(V = NotVertex)
{
break;
}
T[V].Known = true;
for each W adjacent to V
{
if(!T[W].Known)
{
if(T[V].Dist + Cvw < T[W].Dist)
{
Decrease(T[W].Dist to T[V].Dist + Cvw);
T[W].Path = V;
}
}
}
}
}
例题
class Solution {
public:
struct Edge
{
int u,v,d;
Edge(int from,int to,int dis)
: u(from),
v(to),
d(dis)
{
}
};
struct heapNode
{
int u,d;
bool operator < (const heapNode& rhs) const
{
return d > rhs.d;
}
};
int networkDelayTime(vector<vector<int>>& times, int N, int K)
{
priority_queue<heapNode> que;
vector<Edge> edges;
vector<vector<int>> g(N,vector<int>());
vector<int> d(N,INT_MAX);
d[K-1] = 0;
vector<int> visited(N,0);
for(int i = 0; i < times.size();++i)//建图
{
edges.push_back(Edge{times[i][0]-1,times[i][1]-1,times[i][2]});
g[times[i][0]-1].push_back(edges.size()-1);
}
que.push(heapNode{K-1,0});//先把源节点加进去
while(!que.empty())
{
heapNode node = que.top();
que.pop();
if(visited[node.u])
continue;
visited[node.u] = 1;//标记
for(int i = 0; i < g[node.u].size(); ++i)
{
Edge &edge = edges[g[node.u][i]];
if(d[edge.v] > d[edge.u] + edge.d)//更新权值
{
d[edge.v] = d[edge.u] + edge.d;
que.push(heapNode{edge.v,d[edge.v]});
}
}
}
int result = -1;
for(int i = 0; i < d.size(); ++i)
{
if(d[i] > result)
result = d[i];
}
return result == INT_MAX ? -1 : result;//判断是否是连通图
}
};