和小哥哥一起刷洛谷(7)

图论之dijkistra算法

关于dijkstra

维基百科

(动图被作者吃了)

戴克斯特拉算法(英语:Dijkstra’s algorithm,又译迪杰斯特拉算法)由荷兰计算机科学家艾兹赫尔·戴克斯特拉在1956年提出。戴克斯特拉算法使用了广度优先搜索解决赋权有向图的单源最短路径问题。该算法存在很多变体;戴克斯特拉的原始版本找到两个顶点之间的最短路径,但是更常见的变体固定了一个顶点作为源节点然后找到该顶点到图中所有其它节点的最短路径,产生一个最短路径树。该算法常用于路由算法或者作为其他图算法的一个子模块。举例来说,如果图中的顶点表示城市,而边上的权重表示城市间开车行经的距离,该算法可以用来找到两个城市之间的最短路径。

该算法的输入包含了一个有权重的有向图 G,以及G中的一个来源顶点 S。我们以 V 表示 G 中所有顶点的集合。每一个图中的边,都是两个顶点所形成的有序元素对。(u, v) 表示从顶点 u 到 v 有路径相连。我们以 E 表示G中所有边的集合,而边的权重则由权重函数 w: E → [0, ∞] 定义。因此,w(u, v) 就是从顶点 u 到顶点 v 的非负权重(weight)。边的权重可以想像成两个顶点之间的距离。任两点间路径的权重,就是该路径上所有边的权重总和。已知 V 中有顶点 s 及 t,Dijkstra 算法可以找到 s 到 t 的最低权重路径(例如,最短路径)。这个算法也可以在一个图中,找到从一个顶点 s 到任何其他顶点的最短路径。

最初的戴克斯特拉算法不采用最小优先级队列,时间复杂度是$O(|V|^2)$其中$|V|$为图的顶点个数。通过斐波那契堆实现的戴克斯特拉算法时间复杂度是$O(|E|+|V|\log |V|)$(其中|E|是边数) 。对于不含负权的有向图,这是目前已知的最快的单源最短路径算法。

伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
声明优先队列&vis数组;
距离全设为无限;
起点入队;
起点设为零;
while(队列非空){
	cur=最小项;
	u=队列中最小的编号;
	if(u去过)continue;
	u标为访问过;
	for(int i=0;i<u的出度;i++){
		v=这个点的编号;
		w=u到这个点的权值;
		if(v访问过)continue;
		if(u的最短路+w<v目前的最短路){
			更新v的最短路;
			v入队;
		}
	}
}

单源最短路径(标准版)

传说中专门卡spfa的一道题~

题目描述

给定一个 N 个点,M 条有向边的带非负权图,请你计算从 S 出发,到每个点的距离。

数据保证你能从 S 出发到任意点。

输入输出格式

输入格式:

第一行为三个正整数 N, M, S。 第二行起 M 行,每行三个非负整数 ui,vi,wi,表示从 ui 到 vi 有一条权值为 wi的边。

输出格式:

输出一行 N 个空格分隔的非负整数,表示 S 到每个点的距离。

样例:

输入:

1
2
3
4
5
6
7
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

输出:

1
0 2 4 3 

思路

模版题还有思路?

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#include<set>
#include<vector>
using namespace std;
struct Edge;
const int NR=100005;
int d[NR];
vector<Edge> adj[NR];


struct Node{//用于将优先队列从小到大排列的结构体 
    int id,dis;
    Node(int id,int dis):id(id),dis(dis){}
    bool operator < (const Node& b)const{//重载小于号,使得优先队列从小到大排序 
        return this->dis > b.dis;
    } 
};
struct Edge{//存储权值的结构体(可以用pair代替) 
    int v,w;
    Edge(int v,int w):v(v),w(w){}
};


void dijkstra(int s){
    priority_queue<Node> q;//优先队列 
    bool vis[NR];//是否去过 
    memset(vis,0,sizeof(vis));
    memset(d,0x4f4f4f4f,sizeof(d));//距离全设为无限 

    
    d[s]=0;q.push(Node(s,0));//起点入队
    while(!q.empty()){
        Node cur=q.top();//取出队列中距离最短的 
        q.pop(); 
        int u=cur.id;//u为当前点号 
        
        if(vis[u])continue;//若去过,则跳过 
        vis[u]=1;//标记已经去过
        
        for(int i=0;i<adj[u].size();i++){
            int v=adj[u][i].v;
            int w=adj[u][i].w;
            if(vis[v]) continue;//若去过,则跳过 
            if(d[u]+w < d[v]){//进行松弛 
                d[v]=d[u]+w;
                q.push(Node(v,d[v]));
            }
        }
    }
}
int main()
{
    int n,m,start;
    scanf("%d%d%d",&n,&m,&start);
    for(int i=0;i<m;i++){
        int st,en,w;
        scanf("%d%d%d",&st,&en,&w);
        adj[st].push_back(Edge(en,w));
    }
    dijkstra(start);
    for(int i=1;i<=n;i++) printf("%d ",d[i]);
    return 0;
}