最短路算法

在这里插入图片描述

1-floyd

在这里插入图片描述
在这里插入图片描述
floyed传递闭包
判断图中两点之间是否可达

for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			f[i][j]|=f[i][k]&f[k][j];

for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)if(f[i][k])
		for(int j=1;j<=n;j++)if(f[k][j])
			f[i][j]=true;

拓展

在这里插入图片描述
& 当然spfa也可以单源最短路的最短路数量

2-dijkstra

  1. 范围:正权边,复杂度(n+m)logn
    https://www.luogu.org/problemnew/show/P3371
int dis[N];
bool vis[N];//两个集合{s,t}
priority_queue <pair<int,int> > q;// t集合里,到s任意一点的距离的点(按距离近远排序)
void dijkstra(int s)
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));// 有没有被放进s集合里
	dis[s]=0;
	q.push(make_pair(0,s));
	while(!q.empty())
	{
		int u=q.top().second;q.pop();
		if(vis[u]) continue;
		vis[u]=true;//用过他之后就把他放进s里
		for(int i=head[u];i;i=edge[i].nxt)
		{
			int v=edge[i].v;
			int w=edge[i].w;
			if(dis[u]+w<dis[v])
			{
				dis[v]=dis[u]+w;
				q.push(make_pair(-dis[v],v));//更新每个点的远近,用于找下一个离s最近的点
			}
		}
	}
}

3-SPFA

范围:单源最短路,可以做有负权边的图
复杂度:O(km)注意这个K可大可小

https://www.luogu.org/problemnew/show/P3371

queue <int> q;
int dis[N];
bool vis[N];
void spfa(int s)
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	q.push(s);
	dis[s]=0;
	vis[s]=true;//表示s在可更新别的点的队列中
	while(!q.empty())//队列不为空
	{
		int u=q.front();
		q.pop();
		vis[u]=false;//不在队列
		for(int i=head[u];i;i=edge[i].nxt)
		{
			int v=edge[i].v;
			int w=edge[i].w;
			if(dis[u]+w<dis[v])
			{
				dis[v]=dis[u]+w;
				if(!vis[v])//如果不在队列
				{
					q.push(v);//就放进队列
					vis[v]=true;
				}
			}
		}
	}
}

拓展
spfa可以判负环,只需要在q.push(v)这个地方记录一下v被push了多少次就可以了,如果push了n次,就出现了负环

优化

https://www.cnblogs.com/bljfy/p/9262309.html
具体的有SLF和LLL优化
SLF优化15%~20%:
if(dis[v]<dis[u]) push_front
else push_back

SLF+LLL优化50%

优化过后的代码
deque <int> q;
int dis[N];
bool vis[N];
void spfa(int s)
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	q.push_front(s);
	dis[s]=0;
	vis[s]=true;//表示s在可更新别的点的队列中
	while(!q.empty())//队列不为空
	{
		int u=q.front();
		q.pop_front	();
		vis[u]=false;//不在队列
		for(int i=head[u];i;i=edge[i].nxt)
		{
			int v=edge[i].v;
			int w=edge[i].w;
			if(dis[u]+w<dis[v])
			{
				dis[v]=dis[u]+w;
				if(!vis[v])//如果不在队列
				{
					if(dis[v]<dis[q.front()] q.push_front(v);
					else q.push_back(v);
					//就放进队列
					vis[v]=true;
				}
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值