最短路

1.floyed多源最短路

稳定的\(O(n^3)\)预处理,\(O(1)\)查询。

加深理解:floyed的最外层枚举k时,k是任意枚举的,也就是说k可以用来维护其他操作,如赋给每个点一个点权,sort一下,再跑floyed,此时的k就可以作为走过路径的点权最大值,可与最短路一起维护。

点击查看代码
for(int k=1;k<=n;k++)
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
		}
	}
}

2.dij单源最短路

可分为朴素版和堆优化版,朴素版的复杂度为\(O(n^2)\),而堆优化版则为\(mlogn\),做题的时候要做好取舍,总有一些丧心病狂的出题者会卡堆优化。
一般来说是dis[i][j],但具体题可以把最短路当做DP来做,我们就可以给它加状态来维护更多信息。

从教练那里直接搬过来了
朴素版

点击查看代码
//初始化
#include <bits/stdc++.h>
using namespace std;

const int maxn = 510;
const int inf = 0x7f7f7f7f;

int n = 0, m = 0;
int g[maxn][maxn] = {};	//朴素版的dijkstra算法多用与稠密图,因此用邻接矩阵存图
int dis[maxn] = {};	//存储1号点到每个点的最短距离
int vis[maxn] = {}; //存储每个点的最短路是否已经确定

//求1号点到n号点的最短路
void dij()
{
	memset(dis, 0x3f, sizeof(dis));
	dis[1] = 0;
	
	for(int i=1; i<n; i++)
	{
		int t = -1;
		//在还未确定最短路的点中,寻找距离最小的点
		for(int j=1; j<=n; j++)
		{
			if(!vis[j] && (t==-1 || dis[t]>dis[j])) t = j;
		}
		
		//用t更新其他点的距离
		for(int j=1; j<=n; j++)
		{
			dis[j] = min(dis[j], dis[t] + g[t][j]);
		}
		vis[t] = true;
	}
}

int main()
{	
	int x = 0, y = 0, z = 0;
	scanf("%d%d", &n, &m);
	memset(g, 0x3f, sizeof(g));
	for(int i=1; i<=n; i++) g[i][i] = 0;
	for(int i=1; i<=m; i++)
	{
		scanf("%d%d%d", &x, &y, &z);
		g[x][y] = min(g[x][y], z);
	}
	
	dij();
	if(dis[n] == 0x3f3f3f3f) printf("-1");
	else printf("%d", dis[n]);
    
	return 0;
}

堆优化版
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=105;
const int M=5000;



int h[N],to[M],nxt[M],w[M],tot;
void add(int x,int y,int dt)
{
	tot++;
	w[tot]=dt;
	to[tot]=y;
	nxt[tot]=h[x];
	h[x]=tot;
}
int dis[N];
bool vis[N];
priority_queue< pair<int,int> >q;
void dij()
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[1]=0;
	q.push(make_pair(-dis[1],1));
	while(!q.empty())
	{
		int x=q.top().second;
		q.pop();
		vis[x]=1;
		for(int i=h[x];i;i=nxt[i])
		{
			int y=to[i];
			if(dis[y]>dis[x]+w[i])
			{
				dis[y]=dis[x]+w[i];
				if(!vis[y])
				{
					q.push(make_pair(-dis[y],y));
				}
			}
		}
	}
}
int main()
{
	int n,m;
	cin>>n>>m;
	
	for(int i=1;i<=m;i++)
	{
		int x,y,dt;
		cin>>x>>y>>dt;
		add(x,y,dt);
		add(y,x,dt);
	}
	
	dij();
	
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(dis[i]==0x3f)
		{
			cout<<-1;
			exit(0);
		}
		else
		{
			ans=max(ans,dis[i]);
		}
	}
	cout<<ans;
}

3.spfa

spfa相比于dij的优点是可以判负环,可以跑最长路

没什么好说的,上板子

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2600;
const int M=15000;
int n,m;
int h[N],to[M],nxt[M],w[M],cnt;
void add(int x,int y,int dt)
{
	cnt++;
	w[cnt]=dt;
	to[cnt]=y;
	nxt[cnt]=h[x];
	h[x]=cnt;
} 
int dis[N],vis[N];
queue<int>q;
void spfa(int x)
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[x]=0;
	q.push(x);
	vis[x]=1;
	while(!q.empty())
	{
		x=q.front();
		vis[x]=0;
		q.pop();
		for(int i=h[x];i;i=nxt[i])
		{
			int y=to[i];
			if(dis[y]>dis[x]+w[i])
			{
				dis[y]=dis[x]+w[i];
				if(!vis[y])
				{
					q.push(y);
					
				}
			}
		}
	} 
}
int main()
{
	int n,m,ts,te;
	cin>>n>>m>>ts>>te;
	for(int i=1;i<=m;i++)
	{
		int x,y,dt;
		cin>>x>>y>>dt;
		add(x,y,dt);
		add(y,x,dt);
	}
	spfa(ts);
	cout<<dis[te];
}
posted @ 2024-07-13 19:45  zhengchenxi  阅读(22)  评论(0编辑  收藏  举报