最短路径算法

Floyd算法

运用了动态规划思想

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(g[i][j]>g[i][k]+g[k][j])
					g[i][j]=g[i][k]+g[k][j];
			}
		}
	}
}

时间复杂度过高( O 3 O^3 O3),只使用于n≤100的数据。

时间复杂度:( O 3 O^3 O3)

空间复杂度:( O 2 O^2 O2)

算法特点:解决多源最短路径的问题

局限性:能够处理负边权的图,但是不能处理含负环的图(负环不存在最短路径)


Dijkstra算法

基于贪心思想

基本思想:通过贪心思想找出距离源点最近的顶点,再通过该顶点去作为中转顶点来找到下一个距离源点最近的顶点,如此反复直到所有的顶点到源点的距离都被确定。

用数组 d i s [ i ] dis[i] dis[i]表示从源点到i的距离, v i s [ i ] vis[i] vis[i]表示是否访问过i节点。

在这里插入图片描述

dis[]和vis[]初始化:
dis[i]=a[1][i];
dis[1]=0;
vis[1]=1;
松弛算法:
if(dis[G]>dis[F]+a[F][G])
    dis[G]=dis[F]+a[F][G];

代码:

#include<bits/stdc++.h>
using namespace std;

int n,m;
int a[105][105];
int dis[10005];
int vis[105];
int s1,t;

int main(){
	memset(a,0x3f,sizeof(a));
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,y,z;
		cin>>x>>y>>z;
		a[x][y]=z;
		a[y][x]=z;
	}
	cin>>s1>>t;
	for(int i=1;i<n;i++)	dis[i]=a[s1][i];
	dis[s1]=0;
	vis[s1]=1;
	for(int i=1;i<=n;i++){
		int Min=0x3f3f3f3f;
		int s;
		for(int j=1;j<=n;j++){
			if(dis[j]<Min&&vis[j]==0){
				Min=a[s1][j];
				s=j;
			}
		}
		vis[s]=1;
		for(int j=1;j<=n;j++){
			if(vis[j]==0){
				dis[j]=min(dis[j],dis[s]+a[s][j]);
			}
		}
	}
	cout<<dis[t];
	return 0;
}

可以使用堆优化,即用priority_queue储存,依次选取离源点的最小值进行操作

见:Dijkstra堆优化 - CaptainLi - 博客园 (cnblogs.com)


beel-man ford

#include<bits/stdc++.h>
using namespace std;
#define inf 100000000

struct edge{
	int x,y,z;
}edge[101];

int n,e,dis[101];

int main(){
	cin>>n>>e;
	for(int i=1;i<=e;i++)	cin>>edge[i].x>>edge[i].y>>edge[i].z;
	for(int i=1;i<=n;i++)	dis[i]=inf;
	dis[1]=0;
	for(int i=1;i<=n-1;i++){
		bool done=0;
		for(int j=1;j<=e;j++){
			if(dis[edge[i].y]>dis[edge[i].x]+edge[i].z){
				dis[edge[i].y]=dis[edge[i].x]+edge[i].z;
				done=1;
			}
		}
		if(done==0)	break;
	}
}

SPFA

SPFA算法是Beelman-Ford算法的队列优化算法,通常用于求解含负边权的单源最短路径,以及判断负环。在最坏情况下,SPFA算法的时间复杂度和空间复杂度和Bellman-Ford算法相同,为 O ( n m ) O(nm) O(nm),但在稀疏图上运行效率较高。

思路:

  1. 数据结构。链式前向星存储图, d i s [ i ] dis[i] dis[i]记录从源点到节点i的最短路径长度, v i s [ i ] vis[i] vis[i]标记节点i是否在队列中, s u n [ i ] sun[i] sun[i]记录节点i的入队次数。
  2. 创建一个队列,源点u入队,标记u在队列中,u的入队次数加1.
  3. 松弛操作。取出队头x,标记x不在队列中。考察x的所有出边 i ( x , v , w ) i(x,v,w) i(x,v,w),如果 d i s [ v ] > d i s [ x ] + e [ i ] . w dis[v]>dis[x]+e[i].w dis[v]>dis[x]+e[i].w,则 d i s [ i ] = d i s [ x ] + e [ i ] . w dis[i]=dis[x]+e[i].w dis[i]=dis[x]+e[i].w。如果节点v不在队列中,如果v的入队次数+1后≥n,则说明有负环,退出;否则v入队,标记v在队列中。
  4. 重复松弛操作,直至队列为空。

链式前向星存储:

int cnt=0;

struct edge{
	int to;
	int dis;
	int next;
}edge[105];

void addedge(int from,int to,int dis){
	edge[++cnt].next=head[from];
	edge[cnt].to=to;
	edge[cnt].dis=dis;
	head[from]=cnt;
}

代码:

#include<bits/stdc++.h>
using namespace std;

int cnt=0;
int vis[105];
int dis[105];
int sum[105];
int head[105];
int n;

struct edge{
	int to;
	int dis;
	int next;
}edge[105];

void addedge(int from,int to,int dis){
	edge[++cnt].next=head[from];
	edge[cnt].to=to;
	edge[cnt].dis=dis;
	head[from]=cnt;
}

bool spfa(int u){
	queue<int>q;
	memset(vis,0,sizeof(vis));
	memset(sum,0,sizeof(sum));
	memset(dis,0x3f,sizeof(dis));
	dis[u]=0;
	vis[u]=1;
	sum[u]++;
	q.push(u);
	while(!q.empty()){
		int x=q.front();
		q.pop();
		vis[x]=0;
		for(int i=head[x];i;i=edge[i].next){
			int v=edge[i].to;
			if(dis[v]>dis[x]+edge[i].dis){
				dis[v]=dis[x]+edge[i].dis;
				if(!vis[v]){
					if(++sum[v]>=n)	return true;//负环退出
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	return false;
}

int main(){
	cin>>n;
	int u,t;
	cin>>u>>t;
	if(!spfa(u))	cout<<dis[t];
	else	cout<<"负环";
	return 0;
}

时间复杂度:最坏情况下是 O ( n m ) O(nm) O(nm),对于稀疏图时间复杂度为 O ( k m ) O(km) O(km),k为一个较小常数

空间复杂度:包含数组edge[],dist[],空间复杂度为 O ( n + m ) O(n+m) O(n+m)

优势:可以判断负环

算法优化

SLF优化

SLF策略(small label first):如果待入队节点是j,队首元素为节点i,若 d i s [ j ] < d i s [ i ] dis[j]<dis[i] dis[j]<dis[i],则将j插入队首,否则插入队尾。

LLL优化

LLL策略(large label last):设队首元素为节点i,队列中所有dis[]的平均值为x,若 d i s [ i ] > x dis[i]>x dis[i]>x,则将节点插入队尾,查找下一元素,直到某一节点i满足 d i s [ i ] ≤ x dis[i]≤x dis[i]x,将节点i出队,进行松弛操作。

SLF和LLL在随机数据上表现优秀,但是在正权图上最坏情况为 O ( n m ) O(nm) O(nm),在负权图上的最坏情况为达到指数级复杂度。

最短路径算法比较:几大最短路径算法比较_shiwei408的博客-CSDN博客

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值