单源最短路 (但愿嘴短路) 是什么?
讲完了多源最短路 (多余按嘴短路),然后就是单源最短路 (但愿嘴短路)
顾名思义,就是从一个源头出发,到达其他点的最短距离 (希望嘴给短路)(区别于多源最短路 (多余按嘴短路))
算法实现
首先,有请弗洛伊德( F l o y d Floyd Floyd)算法
F l o y d Floyd Floyd
不用我讲了吧,这个算法比较麻烦
不建议使用
然后是贝尔曼-福特( B e l l m a n − F o r d Bellman-Ford Bellman−Ford)算法
B e l l m a n − F o r d Bellman-Ford Bellman−Ford
首先看一看
时空复杂度
- 时间复杂度
O ( D o t s ⋅ E d g e ) O(Dots·Edge) O(Dots⋅Edge) - 空间复杂度
S ( E d g e + D o t s 仅供参考,不一定为真 ) S(Edge+Dots\ \text{仅供参考,不一定为真}) S(Edge+Dots 仅供参考,不一定为真)
看完复杂度,接着再来看看方法
其实,他的本质也是
d
p
…
dp\dots
dp…
不过,他的想法是松弛(孙悟空:你是怎么练成精的?如来佛祖:放松,别急)
就是先看经过一个点的最短,再看经过两个点的最短, … … \dots\ \dots … …,最后看经过 n − 1 n-1 n−1个点的最短
至于存边 … \dots …那就边集数组
转移方程
B F n , E d g e [ i ] . v = m i n { B F n − 1 , E d g e [ i ] . v , B F n − 1 , E d g e [ i ] . u + E d g e [ i ] . w } BF_{n,\ Edge[i].v}=min\{BF_{n-1,\ Edge[i].v}, \ BF_{n-1,\ Edge[i].u}+Edge[i].w\} BFn, Edge[i].v=min{BFn−1, Edge[i].v, BFn−1, Edge[i].u+Edge[i].w}
降维
S ( E d g e ) S(Edge) S(Edge)是因为边集数组,而 S ( D o t s ) S(Dots) S(Dots)是因为 B F l i s t BF\ list BF list的存在,那我们就要降维,然后我们便惊喜的发现, n n n是一个没用的东西!我们赶紧删了
代码
未优化
int n,m,dis[N];
struct ed{
int u,v,wt;
}edge[N];
bool Bellman_ford(int start){
for(int i=1;i<=n;i++)
dis[i]=0x3f3f3f3f3f3f3f3f;
dis[start]=0;
for(int i=1;i<=n;i++)
for(int k=1;k<=ss;k++){
ed e=edge[k];
if(dis[e.v]>dis[e.u]+e.wt)
dis[e.v]=dis[e.u]+e.wt;
}
for(int i=1;i<=ss;i++){
ed e=edge[i];
if(dis[e.v]>1e15||dis[e.u]>1e15)
continue;
if(dis[e.v]>dis[e.u]+e.wt)
return true;
}
return false;
}
优化
```cpp
int n,m,dis[N];
struct ed{
int u,v,wt;
}edge[N];
bool Bellman_ford(int start){
for(int i=1;i<=n;i++)
dis[i]=0x3f3f3f3f3f3f3f3f;
dis[start]=0;
bool flag;
for(int i=1;i<=n;i++){
flag=true;
for(int k=1;k<=ss;k++){
ed e=edge[k];
if(dis[e.v]>dis[e.u]+e.wt)
dis[e.v]=dis[e.u]+e.wt,flag=false;
}
if(flag)
break;
}
for(int i=1;i<=ss;i++){
ed e=edge[i];
if(dis[e.v]>1e15||dis[e.u]>1e15)
continue;
if(dis[e.v]>dis[e.u]+e.wt)
return true;
}
return false;
}
(均可判负环)
D i j k s t r a Dijkstra Dijkstra
D
i
j
k
s
t
r
a
Dijkstra
Dijkstra算法是解决单源最短路径问题的贪心算法
它先求出长度最短的一条路径,再参照该最短路径求出长度次短的一条路径
直到求出从源点到其他各个顶点的最短路径。
时空复杂度
- 时间复杂度
O ( E d g e 2 + E d g e ⋅ D o t s ) O(Edge^2+Edge·Dots) O(Edge2+Edge⋅Dots) - 空间复杂度
S ( E d g e + 2 D o t s 仅供参考,不一定为真 ) S(Edge+2Dots\ \text{仅供参考,不一定为真}) S(Edge+2Dots 仅供参考,不一定为真)
上代码
void Dijkstra(int start){
for(int i=1;i<=n;i++)
dis[i]=kkk;
dis[start]=0;
for(int i=1;i<=m;i++){
int min_dis=1e15,pos;
for(int j=1;j<=n;j++)
if(vis[j]==false&&dis[j]<min_dis)
pos=j,min_dis=dis[j];
if(min_dis==1e15)
return;
else
vis[pos]=true;
for(int j=1;j<=m;j++){
ed e=edge[j];
dis[e.v]=min(dis[e.v],dis[e.u]+e.wt);
}
}
}
当然这个还有堆优化,我不会(雾)
好了,现在你学废单源最短路 (但愿嘴短路) 了吗?