最短路径的三种算法 (2)

最短路径的三种算法

我们更新dist数组后结果如上。

Dist[2] = min(dist[2], dist[1]+(1->2的权值))

Dist[3] = min(dist[3], dist[1]+(1->3的权值))

我们从数组中找一个最小的数值。上图中的点2,那么dist[2]已经可以确定了。因为边最短,走其他的路绕回来肯定路更长。

最短路径的三种算法

通过点2的边,我们可以更新dist数组,如果边能使得dist数值变小

(2)能到达3和4.

Dist[4]=min(dist[4], dist[2] + (2->4的权值))

Dist[3]=min(dist[3], dist[2] + (2->3的权值))

最短路径的三种算法

我们发现原来的dist[3]=4被dist[2]+(2->3的边)=3覆盖

Dist[4]=inf被dist[2]+(2->4的边)=7覆盖。

然后我们在选一条最短边。

最短路径的三种算法

把点3加入集合。扩展的两条边更新dist数组。

最短路径的三种算法

继续找最小

最短路径的三种算法

Dist数组计算完成。

在数据集合中选最小的数我们用优先队列logn,每次都能确定一个点,总过n个点。总复杂度O(nlogn)

写法和大部分和周三的prim算法几乎一模一样的,也分O(n^2)的版本和O(nlogn)优化的版本。一般肯定写快的O(nlogn)的;

//比较挫的O(N^2)版本,可能比较好理解

int dist[maxn], vis[maxn];

int dijkstra(int s, int t) { //从s->t的最短路径,无法到达反回-1

for(int i = 0; i < n; i ++ ) {

dist[i] = inf, vis[i] = 0;

}

dist[s] = 0;

for(int k = 1; k <= n; k ++ ) { ///dist数组n个,每次确定一个值

vis[s] = 1;

for(int i = first[s]; ~i; i = edge[i].next) { ///更新dist数组

int to = edge[i].to, w = edge[i].w;

if(!vis[to] && dist[to] > dist[s] + w) {

dist[to] = dist[s] + w;

}

}

int mincost = inf;

for(int i = 0; i < n; i ++ ) { ///找最小

if(!vis[i] && dist[i] < mincost) {

mincost = dist[i];

s = i;

}

}

}

if(dist[t] == inf) {

return -1;

} else {

return dist[t];

}

}

 

//优先队列实现

struct Node {

int to, cost;

Node() {}

Node(int tt, int cc):to(tt), cost(cc) {}

friend bool operator < (const Node &a, const Node &b) {

return a.cost > b.cost;

}

};

int dist[maxn], vis[maxn];

int dijkstra(int s, int t) {

for(int i = 0; i < n; i ++ ) {

dist[i] = inf, vis[i] = 0;

}

priority_queue<Node>que;

que.push(Node(s, 0));

/**

丢进去一个to=s,cost=0的结构体

等价于下面三行,看不懂往下翻附录构造函数

struct Node tmp;

tmp.to = s, tmp.cost = 0;

que.push(tmp);

*/

while(!que.empty()) {

Node now = que.top();

que.pop();

if(!vis[now.to]) {

vis[now.to] = 1;

dist[now.to] = now.cost;

for(int i = first[now.to]; ~i; i = edge[i].next) {

int to = edge[i].to, w = edge[i].w;

if(!vis[to]) {

que.push(Node(to, now.cost + w));

}

}

}

}

if(dist[t] == inf) {

return -1;

} else {

return dist[t];

}

}

 
SPFA算法(Shortest Path Fast Algorithm的缩写)

Ps: SPFA也叫bellman ford的队列优化。但是bellman ford的复杂度比较高。SPFA的平均复杂度是O(n*log2n),复杂度不稳定,在稠密图(边多的图)跑的比dijkstra慢,稀疏图(边少的图)跑的比Dijkstra快。在完全图达到最坏的平方级复杂度。我们学它是因为有些图的边的长度是负数。这时候dijkstra就GG了。

完全图: n个点中如果每个点都与其他n-1有边,无向图中,就有n*(n-1)/2条边。

我们要求一个dist[]数组表示起点,到其他点的最短路径。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zggdps.html