最短路径问题 三种算法板子

本文介绍了三种解决图中单源最短路径问题的算法:Dijkstra、SPFA和Floyd。Dijkstra算法适用于单源最短路径,采用优先队列实现;SPFA算法同样解决单源最短路径,但可能存在延时队列现象;Floyd算法则能处理多源最短路径问题,通过动态规划思想寻找最短路径。这些算法在路径搜索和网络优化等领域有广泛应用。
摘要由CSDN通过智能技术生成

Dijkstra算法

这个算法解决单源最短路问题。

从起点s出发,将与s点相连的点入队,然后更新每一个点的距离。

第二步从入队的点里找一个s到其距离最小的点,然后再以这个点进行拓展更新,如果到达一个点能够将其更新,并且仍未入队,则将这个点入队。

不断地取队里s到其距离最小的点,然后再进行更新。如果更新了的点未入队,则入队。

一直重复到不能够更新位置。

每一次更新,代表会有一个点入队,所以队为空即为全部更新完毕。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>

using namespace std;

const int oo=2147483647;

int n,m,s;
int pi,p[100005],nex[500005],cost[500005],to[500005];
int val[100005];
bool vis[100005];
struct Dij{
	int t,value;
	friend bool operator < (Dij i,Dij j)
	{
		return i.value > j.value;
	}
};

priority_queue<Dij> q;

void in_map(int u,int v,int c)
{
	pi++; nex[pi]=p[u]; p[u]=pi; cost[pi]=c; to[pi]=v;
}

void read_in()
{
	ios::sync_with_stdio(false),cin.tie(0);
	cin>>n>>m>>s;
	for(int i=1;i<=m;i++)
	{
		int x,y,c;
		cin>>x>>y>>c;
		in_map(x,y,c); 
	}
	for(int i=1;i<=n;i++)
	  val[i]=oo;
}

void Dijkstra()
{
	val[s]=0;
	Dij S;
	S.t=s;
	q.push(S);
	while(!q.empty())
	{
		Dij U=q.top();q.pop();
		int u=U.t;
		if(vis[u]) continue;
		vis[u]=true;
		for(int k=p[u],v=to[k];k;k=nex[k],v=to[k])
		{
			if(val[v] > val[u] + cost[k])
			{
				val[v]=val[u]+cost[k];
				Dij V;V.t=v;V.value=val[v];
				q.push(V);
			}
		}
	}
	for(int i=1;i<=n;i++)
	  cout<<val[i]<<' ';
}

int main()
{ 
	read_in();
	Dijkstra();
	return 0;
}

 

 

SPFA算法

SPFA算法虽说好用,但是据说会被一些数据卡。

它还是只是解决单源最短路。

先从源点出发,然后将与源点相连的点更新,如果更新的点仍未入队,则入队。

然后按照入队顺序取队里第一个元素,将与之相连的点进行松弛,如果松弛了的点为入队则继续入队。

#include<iostream>
#include<stdio.h>
#include<queue>
#include<algorithm>

using namespace std;

const int INF=2147483647;
int pi,p[10005],nex[500005],to[500005],cost[500005];
int n,m,s;
int val[10005];
bool vis[10005];
queue<int> q;

void read_into(int u,int v,int c)
{
	pi++; nex[pi]=p[u]; p[u]=pi; to[pi]=v; cost[pi]=c;
}

void read_in()
{
	ios::sync_with_stdio(false),cin.tie(0);
	cin>>n>>m>>s;
	for(int i=1;i<=m;i++)
	{
		int u,v,c;
		cin>>u>>v>>c;
		read_into(u,v,c);
	}
	for(int i=1;i<=n;i++)
	  val[i]=INF;
}

void SPFA()
{
	val[s]=0;vis[s]=true;
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();q.pop();
		vis[u]=false;
		for(int k=p[u],v=to[k];k;k=nex[k],v=to[k])
		{
			if(val[v] > val[u] + cost[k])
			{
				val[v]=val[u]+cost[k];
				if(!vis[v])
				{
					q.push(v);
					vis[v]=true;
				}
			}
		}
	}
	for(int i=1;i<=n;i++)
	  cout<<val[i]<<' ';
}

int main()
{
	read_in();
	SPFA();
	return 0;
}

 

 

Floyd算法

Floyd算法可以解决多源问题,它类似于DP。

假设要找i到j的距离,我们可以找到一个中间点k,用i到k的距离和k到j的距离进行相加得到i到j的距离。

f[i][j]=min(f[i][j],f[i][k]+f[k][j])

利用这个式子来推。

#include<iostream>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
int n,m,s;
int f[10005][10005];
void read_in()
{
	ios::sync_with_stdio(false),cin.tie(0);
	cin>>n>>m>>s;
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	    f[i][j]=INF;
	for(int i=1;i<=m;i++)
	{
		int u,v,c;
		cin>>u>>v>>c;
		f[u][v]=min(f[u][v],c);
	}
}
void Floyd()
{
	
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				  f[i][j]=min(f[i][k]+f[k][j],f[i][j]);
			}
		}
	}
	f[s][s]=0;
	for(int i=1;i<=n;i++)
	  cout<<f[s][i]<<' ';
}
int main()
{
	read_in();
	Floyd();
	return 0;
}

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值