[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;
}
posted @ 2019-11-04 12:13  Rain_142857  阅读(118)  评论(0编辑  收藏  举报