新征程2.19 数据结构:图论之最短路径SPFA,Dijkstra
前言:
今天讲了SPFA和dij。咱们话不多说,直接进入正题。
floyed:ヽ(#`Д´)ノ,所以爱会消失,对吗?
du:(⊙o⊙)…,好吧。其实也讲了floyed,甚至还做了题。
SPFA
SPFA 算法是单源最短路径里面限制最小的一个算法,只要图当中没有负环就可以用 SPFA 算法,一般的最短路问题里面都一定没有负环,如果是正权图建议用迪杰斯特拉算法,如果是负权图用 SPFA 算法。
基本思路就是更新过一个点,再拿这个点去更新其他点,一个点如果没有被更新过的话,那么它去更新其他点一定是没有效果的
每次把哪个点变小了,就把哪个点放到队列里面去,队列里面存储的就是待更新的点,存储方式可以选择用堆、队列. . .都可以,一般使用队列,SPFA 算法是由 Bellman-Ford 算法优化而来的,与迪杰斯特拉算法很像
SPFA 算法时间复杂度最坏是 O(nm),一般是 O(m)。
code
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n,m,s,tot;
const int N=10010,M=500010,inf=1e9;
int dis[N],in[N],head[N],to[M<<1],nt[M<<1],len[M<<1];
queue<int>q;
void add(int x,int y,int z){to[++tot]=y;len[tot]=z;nt[tot]=head[x];head[x]=tot;}
void SPFA(int S)
{
for(int i=1;i<=n;++i)dis[i]=inf;
dis[S]=0;q.push(S);in[S]=1;
while(!q.empty())
{
int x=q.front();q.pop();in[x]=0;
for(int i=head[x];i;i=nt[i])
if(dis[to[i]]>dis[x]+len[i])
{
dis[to[i]]=dis[x]+len[i];
if(!in[to[i]])q.push(to[i]),in[to[i]]=1;
}
}
}
int main()
{
cin>>n>>m>>s;
for(int i=1,u,v,w;i<=m;++i)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
SPFA(s);
for(int i=1;i<=n;++i)printf("%d ",dis[i]==inf?2147483647:dis[i]);
return 0;
}
只要还有人记得SPFA,它就永远不会死。
Dijkstra
Dijkstra算法是一个基于「贪心」、「广度优先搜索」、「动态规划」求一个图中一个点到其他所有点的最短路径的算法,常规迪杰斯特拉算法的时间复杂度 O (n^2) 。
Dijkstra算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
int n,m,s,tot;
const int M=200010,inf=1e9;
int dis[M],vis[M];
vector<int>to[M],len[M];
struct dian
{
int hao,dis;
friend bool operator<(const dian &a,const dian &b){return a.dis>b.dis;}
};
priority_queue<dian>q;
void DIJ(int S)
{
for(int i=1;i<=n;++i)dis[i]=inf;
dis[S]=0;q.push((dian){S,dis[S]});
while (!q.empty())
{
int x=q.top().hao;q.pop();
if(vis[x])continue;vis[x]=1;
for(int i=0,siz=to[x].size();i<siz;++i)
if(dis[to[x][i]]>dis[x]+len[x][i])
{
dis[to[x][i]]=dis[x]+len[x][i];
q.push((dian){to[x][i],dis[to[x][i]]});
}
}
}
int main()
{
cin>>n>>m>>s;
for(int i=1,u,v,w;i<=m;++i)scanf("%d%d%d",&u,&v,&w),to[u].push_back(v),len[u].push_back(w);
DIJ(s);
for(int i=1;i<=n;++i)printf("%d ",dis[i]);
return 0;
}
Floyed
这位更是重量级,拥有高达O(\(n^3\))时间复杂度。受到oier的广泛喜爱,五星上将麦克阿瑟曾经说过,假如我遇到了擅长使用Floyed的敌人,那么我将允许我的士兵当逃兵。因为我知道,会使用Floyed的敌人是无法被打败的。
#include<bits/stdc++.h>
using namespace std;
int i,j,w,m,n,load[101][101];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j)load[i][j]=9999;
else load[i][j]=0;
while(m--)
{
cin>>i>>j>>w;
load[j][i]=load[i][j]=min(load[i][j],w);
}
for(w=1;w<=n;w++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
load[i][j]=min(load[i][w]+load[w][j],load[i][j]);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
cout<<load[i][j]<<' ';
cout<<endl;
}
return 0;
}
本文来自博客园,作者:deviancez,转载请注明原文链接:https://www.cnblogs.com/deviance/articles/18112959