最短路
单元最短路
Dijkstra
原理:贪心
实现
- 先把所有的点到原点的距离设为无穷大.
- 再依次讨论离原点最近的点
- 讨论与这个点相连的边,更新最小值
注意
1.Dijkstra不能用于有负权的图
2.可以用小根堆维护Dis
3.时间复杂度
O
(
N
l
n
N
)
O(NlnN)
O(NlnN)
- 代码实现:
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define H 500005
#define LL long long
int N,M,S,Dis[H];
int ED[H],NT[H],LA[H],LEN[H],tot=0;
bool MK[H];
struct node{int Dis,Num;};
priority_queue<node>Q;
bool operator < (node a,node b){return a.Dis>b.Dis;}
void LB(int u,int v,int d){
ED[++tot]=v;LEN[tot]=d;NT[tot]=LA[u];LA[u]=tot;
}
void Dijkstra(int s){
for(int i=1;i<=N;i++)Dis[i]=1000000000;
Dis[s]=0;
Q.push( node{Dis[s],s} );
while(!Q.empty()){
node t=Q.top();Q.pop();
int x=t.Num;
if(MK[x])continue;
MK[x]=1;
for(int i=LA[x];i;i=NT[i]){
int y=ED[i];
if(Dis[y]>Dis[x]+LEN[i]){
Dis[y]=Dis[x]+LEN[i];
if(!MK[y])Q.push(node{Dis[y],y});
}
}
}
}
int main(){
scanf("%d%d%d",&N,&M,&S);
for(int i=1;i<=M;i++){
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
LB(u,v,d);
}
Dijkstra(S);
for(int i=1;i<=N;i++)printf("%d ",Dis[i]);
}
SPFA
原理:边的松弛
实现
1.把所有点到原点的距离设置为无穷大
2.把原点到自己的距离设置为零
3.从原点的边开始松弛,把松弛的边加入队列中
4.不断把队列中的边松弛。
注意:
1.SPFA可以看作是bellman-ford的优化
2.SPFA可以用于有负权的边
3.SPFA可以用来判断负权回路(入队N次说明存在)
4.SPFA可能会被菊花图卡掉
- 代码实现
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define MT(a,b) memset(a,b,sizeof(a))
using namespace std;
const int H=20005,HH=500055;
int Dis[H],N,M,S;
int LA[H],ED[HH],LN[HH],NT[HH],t;
bool Vis[H];queue<int> q;
void LB(int u,int v,int w){ED[++t]=v;LN[t]=w;NT[t]=LA[u];LA[u]=t;}
void SPFA(int S){
MT(Dis,inf);MT(Vis,0);
q.push(S);Vis[S]=1;Dis[S]=0;
while(!q.empty()){
int u=q.front();q.pop();Vis[u]=0;
for(int i=LA[u];i;i=NT[i]){
int v=ED[i];
if(Dis[v]>Dis[u]+LN[i]){
Dis[v]=Dis[u]+LN[i];
if(!Vis[v]){q.push(v);Vis[v]=1;}
}
}
}
}
int main(){
scanf("%d%d%d",&N,&M,&S);
for(int i=1;i<=M;i++){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
LB(u,v,w);
}
SPFA(S);
for(int i=1;i<=N;i++){
if(Dis[i]==inf)printf("2147483647 ");
else printf("%d ",Dis[i]);
}
}
多元最短路
Floyd算法
时间复杂度: O ( N 3 ) O(N^3) O(N3)
- 代码实现:
Map[i][j]=min(Map[i][k]+Map[k][j])