图中最短路算法

本文介绍了三种图中最短路算法:Floyd算法,虽然因为时间复杂度较高不常用,但在特定场景下如无向图最小环中有应用;Dijkstra算法是常用的贪心算法,常配合堆优化解决最短路问题,但不适用于负权重边;SPFA算法在有负边权的情况下仍有其价值,但通常不作为首选的最短路径算法。
摘要由CSDN通过智能技术生成

1.Floyd

由于算法时间复杂度是n^3的,一般不常用,但在无向图最小环中可以用到

设f[i][j]表示i和j之间,经过k条边的最短路径 得到状态转移方程如下

for(register int k(1) ; k<=n ; k=-~k){
    for(register int i(1) ; i<=n ; i=-~i){
		for(register int j(1) ; j<=n ; j=-~j){
			f[i][j] = min(f[i][j],f[i][k]+f[k][j]);
			f[j][i] = f[i][j];
		}
	}
}

2.Dijkstra

基于贪心的一种最短路算法,也是现在竞赛常用的算法用堆优化后时间复杂度O(nlogm)

用dis[u]表示已经找到的源点s到u的最短距离,如果dis[v] > dis[u] + w,用dis[u] + w更新dis[v]

用pair,优先队列优化  但注意,只能不能处理带负边权的图

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
	return x*f;
}
const int M = 500010;
const int inf = 2147483647;
int n,m,s;
int cnt,head[M],vis[M];
long long dis[M];
struct egde{
	int to,nxt,w;
}e[M];
typedef pair<int,int> pir;
priority_queue<pir,vector<pir>,greater<pir> >q;
void add(int u,int v,int w){
	e[++cnt].w = w;
	e[cnt].to = v;
	e[cnt].nxt = head[u];
	head[u] = cnt;
}
void dij(int s){
	for(register int i(1) ; i<=M-1 ; i=-~i) dis[i] = inf; //初始化为正无穷
	dis[s] = 0; //自己到自己的距离为0
	q.push(pir(0,s));
	while(!q.empty()){
		int f = q.top().first,u = q.top().second;
		q.pop();
		if(f!=dis[u]) continue; 
		for(register int i(head[u]) ; i ; i=e[i].nxt){
			int v=e[i].to,w=e[i].w;
			if(dis[v] > dis[u]+w){ //更新
				dis[v] = dis[u]+w;
				q.push(pir(dis[v],v)); //加入队列
			}
		}
	}
}
int main(){
	n=read();m=read();s=read();
	for(register int i(1) ; i<=m ; i=-~i){
		int u,v,w;
		u=read();v=read();w=read();
		add(u,v,w);
	}
	dij(s);
	for(register int i(1) ; i<=n ; i=-~i) printf("%lld ",dis[i]);
	return 0;
}

3.spfa  他已经死了  不不不,在有负边权的情况下或者别的算法中仍然能用到(但最短路尽量不用)

也是一种贪心算法,每次从队首取出一个节点x,遍历与x相通的节点y,更新最小值

#include<bits/stdc++.h>
using namespace std;
const int inf = 2147483647;
int head[100010],dis[100010];
int n,m,s;
int vis[500010];
struct edge{
	int to,next,w;
}e[500100];
int cnt=0;
void add(int u,int v,int w){
	cnt++;
	e[cnt].to = v;
	e[cnt].w = w;
	e[cnt].next = head[u];
	head[u] = cnt;
}
queue<int>q;
void spfa(int s){
	for(int i=1 ; i<=n ; i++){
		dis[i] = inf;
	}
	q.push(s);
	vis[s] = 1;
	dis[s] = 0;
	while(!q.empty()){
		int u=q.front();
		vis[u]=0;
		q.pop();
		for(int i=head[u] ; i ; i=e[i].next){
			int v=e[i].to;
			int w=e[i].w;
			if(dis[v]>dis[u]+w){
				dis[v] = dis[u]+w;
				if(vis[v]==0){
					q.push(v);
					vis[v] = 1;
				}
			}
		}
	}
	return;
}
int main(){
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1 ; i<=m ; i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	spfa(s);
	for(int i=1 ; i<=n ; i++){
		if(dis[i]!=inf){
			printf("%d ",dis[i]);
		}
		else{
			printf("%d ",inf);
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值