0%

最短路学习笔记

总论

最短路算法是常用的图论算法,实现多种多样,且拓展度很好,值得学习,现在指的最短路都是单源最短路。

前置芝士

存图:

  1. 邻接矩阵
  2. 邻接表
  3. 链式前向星(数组模拟链表)

这是练习。

三角形不等式:

对于一个图 $G$,记 $G[i][j]$ 为从 $i$ 到 $j$ 的最短路,则对任意的 $k$,有 $G[i][j]<G[i][k]+G[k][j]$ 。

证明的话很简单,就是定义呗。

不会去手搓数据去。

算法

Floyd

思想基于动规,分别遍历所有点,经过每一个点 k 是否满足三角形不等式,代码复杂度 $O(n^3)$

1
2
3
4
5
6
7
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
}
}
}

SPFA

它死了。,思想其实就是 Bellman-Ford,考试慎用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct node{
int to,next,value;
}e[N*50+10];
void spfa(int s){
memset(d,0x3f,sizeof d);
vis[s]=1;
d[s]=0;
q.push(s);
while(!q.empty()){
int x=q.front();q.pop();vis[x]=0;
for(int i=head[x];i;i=e[i].next){
int y=e[i].to;
if(d[y]>d[x]+e[i].value){
d[y]=d[x]+e[i].value;
if(!vis[y]){
q.push(y);
vis[y]=1;
}
}
}
}
}

代码神似BFS。

Dijkstra

目前最优秀的算法,但无法处理负边权,因为其基于贪心算法,优化后复杂度为 $O(mlogm)$,这个板子一定要熟。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void dij(int s){
memset(d,0x3f,sizeof d);
d[s]=0;
q.push({s,0});
while(!q.empty()){
int x=q.top().num;
q.pop();
if(vis[x])continue;
vis[x]=1;
for(int i=head[x];i;i=e[i].next){
int y=e[i].to;
if(d[y]>d[x]+e[i].value){
d[y]=d[x]+e[i].value;
//vis[y]=1;
q.push({y,d[y]});
}
}
}
}

有两个点要注意一下:

  1. 初始入队是不需要标记是否访问,不然 while 循环不会启动。
  2. 标记的是取出的堆头,不是别的