[Luogu P4779] 单源最短路径(标准版)
以此题为例,总结所有的最短路算法。
Floyd
用w[i][j]记录i到j的最短路,实质上是DP。
记得初始化:存在i->j则w[i][j]=e[i][j],w[i][i]=0,其余w[i][j]=inf。
复杂度O(n^3)。
#include<cstdio>
#include<cstring>
using namespace std;
const int inf=0x7f7f7f7f;
long long w[1010][1010];
int main()
{
int n,m,i,j,k,x,y,z;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
w[i][j]=inf;
}
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
w[x][y]=z;
}
for(i=1;i<=n;i++)w[i][i]=0;
for(k=1;k<=n;k++)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(w[i][j]>w[i][k]+w[k][j])
w[i][j]=w[i][k]+w[k][j];
}
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
printf("%d ",w[i][j]);
printf("\n");
}
return 0;
}
SPFA
类似于bfs,用一个队列来维护被松弛过的点,每次松弛队首元素向外连的点的最短路,并将这些点push到队列里。记录一个vis[i]表示i是否在队列里可以减少入队次数。
复杂度最坏O(n*m)。可以处理负权边,判环,但是如果只求正权图最短路使用Dijkstra更好。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
int read()
{
int x=0;bool f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int inf=0x7f7f7f7f;
struct edge
{
int v,last,w;
}e[2000010];
int in[1000010],cnt=0;
void addedge(int x,int y,int z)
{
e[++cnt].v=y;
e[cnt].last=in[x];
e[cnt].w=z;
in[x]=cnt;
}
queue<int>q;
bool vis[1000010];
int dis[1000010];
void spfa(int st)
{
int i,cur,t;
memset(dis,127,sizeof(dis));
dis[st]=0;
q.push(st);
vis[st]=1;
while(!q.empty())
{
cur=q.front();q.pop();
vis[cur]=0;
for(i=in[cur];i;i=e[i].last)
{
t=e[i].v;
if(dis[t]>dis[cur]+e[i].w)
{
dis[t]=dis[cur]+e[i].w;
if(!vis[t])
{
vis[t]=1;
q.push(t);
}
}
}
}
return;
}
int main()
{
int n,m,i,j,k,x,y,z,S;
n=read(),m=read(),S=read();
for(i=1;i<=m;i++)
{
x=read(),y=read(),z=read();
addedge(x,y,z);
}
spfa(S);
for(i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
Dijkstra
每次更新的是还没访问到的最短路距离最小的点向外连的点。实质是贪心,用堆可以加快速度。复杂度O(nlogn)。不能处理负权边。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
int read()
{
int x=0;bool f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int inf=0x7f7f7f7f;
struct edge
{
int v,last,w;
}e[2000010];
int in[1000010],cnt=0;
void addedge(int x,int y,int z)
{
e[++cnt].v=y;
e[cnt].last=in[x];
e[cnt].w=z;
in[x]=cnt;
}
struct node
{
int dist,pos;
friend bool operator < (node x,node y)
{
return x.dist>y.dist;
}
};
priority_queue<node>q;
int dis[1000010];
bool vis[1000010];
void dijkstra(int st)
{
int i,cur,t;
memset(dis,127,sizeof(dis));
memset(vis,0,sizeof(vis));
while(!q.empty())q.pop();
dis[st]=0;
q.push((node){0,st});
while(!q.empty())
{
cur=q.top().pos;q.pop();
if(vis[cur])continue;
vis[cur]=1;
for(i=in[cur];i;i=e[i].last)
{
t=e[i].v;
if(dis[t]>dis[cur]+e[i].w)
{
dis[t]=dis[cur]+e[i].w;
if(!vis[t])q.push((node){dis[t],t});
}
}
}
return;
}
int main()
{
int n,m,i,j,k,x,y,z,S;
n=read(),m=read(),S=read();
for(i=1;i<=m;i++)
{
x=read(),y=read(),z=read();
addedge(x,y,z);
}
dijkstra(S);
for(i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}