最短路算法流程
2025/7/27大约 7 分钟
最短路算法流程
Floyd
Floyd-Warshall 算法
- 初始化距离矩阵 :
- 对于任意 :
- 若 则
- 否则若存在边 ,则
- 否则
- 对于任意 :
- 遍历所有中间点 ():
- 对每个 ():
- 对每个 ():
- 如果 :
- 如果 :
- 对每个 ():
- 对每个 ():
- 最终 存储 到 的最短路径长度
- 全源最短路径
- 能处理负权边
- 时间复杂度:
朴素 Dijkstra
朴素 Dijkstra 算法
- 初始化:
- ,对于任意 ,
- 集合 (已确定最短路径的点)
- 当 ( 为节点集)时:
- 选取 且 最小
- 在 中加入
- 对 的每个邻居 :
- 如果 :
- 如果 :
- 单源最短路径
- 不能处理负权边
- 时间复杂度:
堆优化 Dijkstra
堆优化 Dijkstra
- 初始化:
- ,对于任意 ,
- 小根堆 插入
- 对于任意 ,
- 当 非空时:
- 弹出 中 最小的
- 如果 :
- 跳过
- 否则:
- 对 的每个邻居 :
- 如果 :
- 在 中加入
- 如果 :
- 单源最短路径
- 不能处理负权边
- 时间复杂度:
代码示例
Floyd
邻接矩阵
const int N=510,M=5010,inf=0x3f3f3f3f;
int n,m,s=1,dis[N],u,v,w,f[N][N];
void init(){
memset(f,0x3f,sizeof f);
for(int i=1;i<=n;i++)
f[i][i]=0;
}
void add(int u,int v,int w){
f[u][v]=min(f[u][v],w);
}
void solve(){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
for(int i=1;i<=n;i++)dis[i]=f[s][i];
}
朴素 Dijkstra
邻接表
const int N=510,M=5010,inf=0x3f3f3f3f;
int n,m,s=1,dis[N],u,v,w;
vector<pair<int,int>>g[N];
bool vis[N];
void init(){
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++)g[i].clear();
dis[s]=0;
}
void add(int u,int v,int w){
g[u].push_back({v,w});
}
void solve(){
for(int i=1;i<=n;i++){
int mi=inf,u=-1;
for(int j=1;j<=n;j++)
if(!vis[j]&&dis[j]<mi)
mi=dis[j],u=j;
vis[u]=1;
for(auto v:g[u])
if(dis[u]+v.second<dis[v.first])
dis[v.first]=dis[u]+v.second;
}
}
链式前向星
const int N=510,M=5010,inf=0x3f3f3f3f;
int n,m,s=1,dis[N],u,v,w;
struct Edge{
int to,w,nxt;
}edge[M];
int cnt,head[N];
void add(int u,int v,int w){
edge[++cnt].to=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
bool vis[N];
void init(){
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
memset(edge,0,sizeof edge);
memset(head,0,sizeof head);
dis[s]=0,cnt=0;
}
void solve(){
for(int i=1;i<=n;i++){
int mi=inf,u=-1;
for(int j=1;j<=n;j++)
if(!vis[j]&&dis[j]<mi)
mi=dis[j],u=j;
vis[u]=1;
for(int v=head[u];v;v=edge[v].nxt)
if(dis[u]+edge[v].w<dis[edge[v].to])
dis[edge[v].to]=dis[u]+edge[v].w;
}
}
堆优化 Dijkstra
邻接表
const int N=510,M=5010,inf=0x3f3f3f3f;
int n,m,s=1,dis[N],u,v,w;
struct node{
int id,dis;
bool operator<(const node& x)const{return dis>x.dis;}
};
vector<pair<int,int>>g[N];
priority_queue<node>q;
bool vis[N];
void init(){
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++)g[i].clear();
while(q.size())q.pop();
dis[s]=0;
}
void add(int u,int v,int w){
g[u].push_back({v,w});
}
void solve(){
q.push({s,0});
while(q.size()){
int u=(q.top()).id;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(auto v:g[u])
if(dis[u]+v.second<dis[v.first]){
dis[v.first]=dis[u]+v.second;
q.push({v.first,dis[v.first]});
}
}
}
链式前向星
const int N=510,M=5010,inf=0x3f3f3f3f;
int n,m,s=1,dis[N],u,v,w;
struct Edge{
int to,w,nxt;
}edge[M];
int cnt,head[N];
void add(int u,int v,int w){
edge[++cnt].to=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
struct node{
int id,dis;
bool operator<(const node& x)const{return dis>x.dis;}
};
vector<pair<int,int>>g[N];
priority_queue<node>q;
bool vis[N];
void init(){
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
memset(edge,0,sizeof edge);
memset(head,0,sizeof head);
dis[s]=0,cnt=0;
while(q.size())q.pop();
}
void solve(){
q.push({s,0});
while(q.size()){
int u=(q.top()).id;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(int v=head[u];v;v=edge[v].nxt)
if(dis[u]+edge[v].w<dis[edge[v].to]){
dis[edge[v].to]=dis[u]+edge[v].w;
q.push({edge[v].to,dis[edge[v].to]});
}
}
}
Bellman-Ford
邻接表
const int N=510,M=5010,inf=0x3f3f3f3f;
int n,m,s=1,dis[N],u,v,w;
vector<pair<int,int>>g[N];
void init(){
memset(dis,0x3f,sizeof dis);
for(int i=1;i<=n;i++)g[i].clear();
dis[s]=0;
}
void add(int u,int v,int w){
g[u].push_back({v,w});
}
bool solve(){
for(int i=1;i<n;i++)
for(int j=1;j<=n;j++)
for(auto v:g[j])
if(dis[j]+v.second<dis[v.first])
dis[v.first]=dis[j]+v.second;
for(int j=1;j<=n;j++)
for(auto v:g[j])
if(dis[j]+v.second<dis[v.first])
return 1;
return 0;
}
链式前向星
const int N=510,M=5010,inf=0x3f3f3f3f;
int n,m,s=1,dis[N],u,v,w;
struct Edge{
int to,w,nxt;
}edge[M];
int cnt,head[N];
void add(int u,int v,int w){
edge[++cnt].to=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
void init(){
memset(dis,0x3f,sizeof dis);
memset(edge,0,sizeof edge);
memset(head,0,sizeof head);
dis[s]=0,cnt=0;
}
bool solve(){
for(int i=1;i<n;i++)
for(int j=1;j<=n;j++)
for(int v=head[j];v;v=edge[v].nxt)
if(dis[j]+edge[v].w<dis[edge[v].to])
dis[edge[v].to]=dis[j]+edge[v].w;
for(int j=1;j<=n;j++)
for(int v=head[j];v;v=edge[v].nxt)
if(dis[j]+edge[v].w<dis[edge[v].to])
return 1;
return 0;
}
SPFA
邻接表
const int N=510,M=5010,inf=0x3f3f3f3f;
int n,m,s=1,dis[N],u,v,w;
vector<pair<int,int>>g[N];
queue<int>q;
bool inq[N];
int cnt[N];
void init(){
memset(dis,0x3f,sizeof dis);
memset(inq,0,sizeof inq);
memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;i++)g[i].clear();
while(q.size())q.pop();
dis[s]=0;
}
void add(int u,int v,int w){
g[u].push_back({v,w});
}
bool solve(){
q.push(s);
inq[s]=1;
while(q.size()){
int u=q.front();
q.pop();
inq[u]=0;
if(cnt[u]>m)return 1;
for(auto [v,w]:g[u]){
if(dis[u]+w<dis[v]){
dis[v]=dis[u]+w;
cnt[v]=cnt[u]+1;
if(!inq[v])q.push(v),inq[v]=1;
}
}
}
return 0;
}
链式前向星
const int N=510,M=5010,inf=0x3f3f3f3f;
int n,m,s=1,dis[N],u,v,w;
struct Edge{
int to,w,nxt;
}edge[M];
int tot,head[N];
void add(int u,int v,int w){
edge[++tot].to=v;
edge[tot].w=w;
edge[tot].nxt=head[u];
head[u]=tot;
}
queue<int>q;
bool inq[N];
int cnt[N];
void init(){
memset(dis,0x3f,sizeof dis);
memset(inq,0,sizeof inq);
memset(cnt,0,sizeof cnt);
memset(edge,0,sizeof edge);
memset(head,0,sizeof head);
while(q.size())q.pop();
dis[s]=0,tot=0;
}
bool solve(){
q.push(s);
inq[s]=1;
while(q.size()){
int u=q.front();
q.pop();
inq[u]=0;
if(cnt[u]>m)return 1;
for(int v=head[u];v;v=edge[v].nxt){
if(dis[u]+edge[v].w<dis[edge[v].to]){
dis[edge[v].to]=dis[u]+edge[v].w;
cnt[edge[v].to]=cnt[u]+1;
if(!inq[edge[v].to])q.push(edge[v].to),inq[edge[v].to]=1;
}
}
}
return 0;
}
使用示例
#include<bits/stdc++.h>
using namespace std;
/*Shortest Path Code*/
int main(){
cin>>n>>m;
init();
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
add(u,v,w);
}
solve();
for(int i=1;i<=n;i++)
cout<<(dis[i]==inf?-1:dis[i])<<'\n';
return 0;
}
提示
Bellman-Ford、SPFA 的 solve()
函数有返回值,可以判断负环。
注意
邻接表 SPFA 代码中的 for(auto [v,w]:g[u])
在 C++17 及以上版本才能使用。