最短路的三种解法
1.单源最短路
迪杰斯特拉(nn) 和 Spfa(nm)
一般使用迪杰斯特拉+堆优化,时间复杂度为(n+m)log2n,但是只用于不含有负权的边的求解最短
步骤:
1.建立边,dis数组无穷化,dis[start]=0;
2.优先队列加入边,当pr.dis != dis[pr.pos] 时continue,因为已经有更小的路径连接当前点了,所有不需要了
3.更新dis,并且push进去
优先队列排序的关键代码
bool operator < (const node &x)const
{
return x.dis < dis;
}
#include<bits/stdc++.h>
using namespace std;
struct node
{
int v,w,next;
} a[500010];
struct nodee
{
int dis,pos;
bool operator < (const nodee &x)const
{
return x.dis <dis;
}
};
priority_queue<nodee>q;
int head[100010];
int dis[100010];
int tot = 0;
const int inf = 1e9+7;
int n;
void dj(int s)
{
dis[s] = 0;
nodee e;
e.dis = 0;
e.pos = s;
q.push(e);
while(!q.empty())
{
nodee fr = q.top();
q.pop();
int now = fr.pos;
int len = fr.dis;
if(dis[now]!=len)continue;
for(int j = head[now] ; j != 0; j = a[j].next)
{
int y = a[j].v;
int z = a[j].w;
if(dis[y] >dis[now] + z)
{
dis[y] = dis[now] + z;
nodee temp;
temp.pos = y;
temp.dis = dis[y];
q.push(temp);
}
}
}
};
int main()
{
int m,s;
scanf("%d%d%d",&n,&m,&s);
for(int i=1; i<=n; i++)
{
head[i] = 0;
dis[i]=inf;
}
for(int i=1; i<=m; i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
++tot;
a[tot].v = y;
a[tot].w = z;
a[tot].next = head[x];
head[x] = tot;
}
dj(s);
for(int i = 1; i <= n; i++)
{
printf("%d ",dis[i]);
}
printf("\n");
}
Spfa
使用队列bfs,vis数组看当前点是否在队列中,如果dis[y] > dis[k] + z &&不在队列中,就加入并且使它标记为1
#include<bits/stdc++.h>
#define sc scanf
#define pr printf
using namespace std;
const int inf=2147483647;
int vis[10010];
int dis[10010];
struct node{
int to;
int z;
int next;
}a[500010];
int head[10010];
queue<int>q;
void spfa(int s){
dis[s]=0;
q.push(s);
vis[s]=1;
while(!q.empty()){
int now=q.front();
vis[now]=0;
q.pop();
for(int i=head[now];i!=-1;i=a[i].next){
int to=a[i].to;
int z=a[i].z;
if(dis[to]>dis[now]+z){
dis[to]=dis[now]+z;
if(!vis[to]){
vis[to]=1;
q.push(to);
}
}
}
}
}
int main(){
int n,m,s;
sc("%d%d%d",&n,&m,&s);
for(int i=1;i<=n;i++){
head[i]=-1;
dis[i]=inf;
vis[i]=0;
}
int top=0;
for(int i=1;i<=m;i++){
int u,v,w;
sc("%d%d%d",&u,&v,&w);
a[top].next=head[u];
a[top].to=v;
a[top].z=w;
head[u]=top;
top++;
}
spfa(s);
for(int i=1;i<=n;i++){
printf("%d ",dis[i]);
}
printf("\n");
return 0;
}
多源最短路
佛洛依德
思路就是 我假如要从i到j,要使更短我们就要借助中间的一个点k是的i->k->j的路程小于i->j
关键代码
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dis[i][k]+dis[k][j]<dis[i][j]){
dis[i][j] = dis[i][k] +dis[k][j];
}
}
}
}