搜索与图论第六期 最短路问题

news/2024/7/15 18:09:03 标签: 图论


前言

最短路问题真的很重要很重要希望大家都能够完全掌握所有最短路算法!!

一、最短路问题的分类

Dijkstra:


Dijkstra算法是一种著名的图算法,主要用于求解有权图中的单源最短路径问题。它由荷兰计算机科学家艾兹赫尔·戴克斯特拉(Edsger Wybe Dijkstra)在1956年首次提出。Dijkstra算法的核心思想是通过以下步骤逐步构建最短路径树:

初始化:创建一个空白的最短路径字典,其中每个节点的距离设置为无穷大,起始节点的距离设置为0。
标记已访问节点:创建一个已访问节点集合,并将所有节点都加入这个集合。
更新距离:对于未被访问的节点,从其未被访问的邻居中选择距离当前节点最近的邻居,将其标记为已访问,并且更新该邻居节点的距离。
重复上述步骤:直到所有节点都被访问,此时已经得到了从起始节点到所有其他节点的最短路径。
Dijkstra算法的特点在于它能够处理图中的负权边,但通常会忽略这些边,因为它们不会影响最终的路径长度计算。如果图中存在负权边,可能需要使用其他的图算法,如Bellman-Ford算法。此外,Dijkstra算法的时间复杂度通常是O(V^2),其中V是节点数量,但如果使用优先队列来优化,时间复杂度可以减少到O(Elog(V)),其中E是边数。1

在实际编程实现时,可以使用不同的数据结构和算法来实现Dijkstra算法,以提高效率。例如,可以使用优先队列或堆来加速松弛操作,从而减少总体时间复杂度。2

总结一下,Dijkstra算法的主要优点是可以有效地解决单源最短路径问题,并且在大多数情况下不需要考虑负权边的影响。它在多个领域有着广泛的应用,包括路线规划、网络路由、资源分配等。

Bellman-Ford算法:

贝尔曼-福特算法(Bellman-Ford Algorithm)是一种用于求解单源最短路径问题的算法,由理查德·贝尔曼(Richard Bellman)和莱斯特·福特(Lester Ford)共同创立。该算法能够处理图中的负权边,并具有简单的实现方式和较高的时间复杂度。贝尔曼-福特算法的核心思想是通过多次松弛操作来确定所有可能的最短路径。每次迭代中,算法会更新所有节点的距离,确保它们符合“三角不等式”,即任意两点间的距离加上第三者的重量小于或等于这两点间距离之和。

尽管贝尔曼-福特算法在处理带负权边的最短路径问题上表现良好,但在某些情况下可能会遇到困难,如当图中存在负权环路时,可能会导致无法找到任何有效的最短路径。此外,虽然它可以处理负权边,但其时间复杂度为 \( O(VE) \),其中 \( V \) 是顶点的数量,\( E \) 是边的数量,这使得它在实践中可能不是最佳选择。

总结来说,贝尔曼-福特算法的主要优点包括支持负权边和简单性,而其主要缺点在于高的时间复杂度。为了提高效率,算法可以进行一些优化措施。需要注意的是,贝尔曼-福特算法有时也被称作 Moore-Bellman-Ford 算法,因为它还涉及到了另一位科学家 Edward F. Moore 的贡献。

SPFA算法:

SPFA算法
SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环

Floyd算法:

floyd算法
Floyd算法,也被称为弗洛伊德算法或插点法,是一种解决加权图中顶点间最短路径问题的算法。它可以处理有向图或负权图(但不能存在负权回路),并同时用于计算有向图的传递闭包。Floyd算法的名称来源于其创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德。

Floyd算法的核心思想是利用动态规划技术来构建一个路径矩阵,这个矩阵包含了图中所有顶点对之间的最短路径长度。算法的基本步骤包括初始化路径矩阵、进行多次更新操作以及最终获取任意两点之间的最短路径。

具体来说,算法会创建两个矩阵:一个存储了顶点对之间的距离,另一个存储了这些距离的逆。在每一次迭代中,都会根据已有的信息更新这两个矩阵。这个过程涉及到多个嵌套的for循环,直到所有的路径都被计算出来为止。

Floyd算法的时间复杂度和空间复杂度分别为O(n^3)和O(n^2),这意味着它在处理大规模网络图时会比较耗时。此外,虽然算法本身不需要回溯路径的具体信息,但它确实可以用来构造出最短路径的详细列表。

总结一下,Floyd算法的主要特点和应用场景如下:

适用范围:适用于有向图或负权图,不能有负权回路。
时间复杂度:O(n^3),即n³次操作。
空间复杂度:O(n^2),即n²个变量。
主要用途:求解任意两点间的最短路径,也可以用于计算传递闭包。
其他应用:在某些情况下,可以用于查找关系的传递闭包。

二、例题

1.朴素Dijkstra:


AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 510;
int g[N][N];
int dis[N];
bool st[N];
int n,m;
int dij()
{
	memset(dis,0x3f,sizeof dis);
	dis[1] = 0;
	for(int i=0;i<n;i++){
		int t = -1;
		for(int j=1;j<=n;j++){
			if(!st[j] && (t==-1 || dis[t]>dis[j]))
				t=j;
		}
		st[t] = true;
		for(int j=1;j <= n;j++){
			dis[j] = min(dis[t]+g[t][j],dis[j]);
		}
	}
	if(dis[n] == 0x3f3f3f3f) return -1;
	return dis[n];
}
int main()
{
    cin>>n>>m;
	memset(g,0x3f,sizeof g);
	while(m--){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		g[a][b] = min(g[a][b],c);
	}
	int t = dij();
	cout<<t<<endl;
	return 0;
}

2、堆优化Dijkstra:

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 15e4+10; 
typedef pair<int ,int>PII;
int h[N],e[N],ne[N],idx,w[N];
int n,m;
int dis[N],st[N];
void add(int a,int b,int c)
{
	e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}

int dij()
{
	memset(dis,0x3f,sizeof dis);
	dis[1] = 0;
	priority_queue<PII,vector<PII>,greater<PII>>heap;
	heap.push({0,1});//距离加顶点;
	while(heap.size()){
	    auto t = heap.top();
		heap.pop();
		int ver = t.second,distance = t.first;
		if(st[ver]) continue;
		st[ver] = true;
		for(int i=h[ver];i!=-1;i= ne[i]){
			int j = e[i];//为了更新其他的边
			if(dis[j] > w[i] + dis[ver] && !st[j]){
				dis[j]  =w[i]+ dis[ver];
				heap.push({dis[j],j});
			}
		}
	}
	if(dis[n] == 0x3f3f3f3f ) return -1;
	return dis[n];
}
int main()
{
	cin>>n>>m;
	memset(h,-1,sizeof h);
	while(m--){
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);
	}
	cout<<dij()<<endl;
	return 0;
}

3、 有边数限制的最短路:

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 520,M = 10010;
int n,m,k;
int dis[N],backup[M];

struct Edge
{
	int a,b,w;
}edges[M];

int bellman_ford()
{
	memset(dis,0x3f,sizeof dis);
	dis[1] = 0;
	for(int i = 0; i < k; i ++){
		memcpy(backup,dis,sizeof dis);
		for(int j=0;j< m;j ++){
	        int a = edges[j].a,b=edges[j].b,w=edges[j].w;
			dis[b] = min(dis[b],backup[a] + w);
		}
	}
	if(dis[n] > 0x3f3f3f3f/2 ) return -1;
	return dis[n];
}
int main()
{
	cin>>n>>m>>k;
	for(int i=0;i<m;i++){
		int a,b,w;
		scanf("%d%d%d",&a,&b,&w);
		edges[i] = {a,b,w};
	}
	int t = bellman_ford();
	if(t == -1) puts("impossible");
	else printf("%d\n",t);
	return 0;
}

4、spfa判断负环:

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 15e4+10; 
typedef pair<int ,int>PII;
int h[N],e[N],ne[N],idx,w[N];
int n,m;
int dis[N],st[N],cnt[N];
void add(int a,int b,int c)
{
	e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}

int spfa()
{
	dis[1] = 0;
	queue<int>q;
	for(int i=1;i<=n;i++){
		st[i]= true;
		q.push(i);
	}
	
	while(q.size()){
		int t = q.front();
		q.pop();
		st[t]  = false;
		for(int i=h[t];i!=-1;i = ne[i]){
			int j= e[i];
			if(dis[j] > dis[t] + w[i]){
				dis[j] = dis[t]+w[i];
				cnt[j] = cnt[t] + 1;
				if(cnt[j]>=n) return true; 
				q.push(j);
				st[j] = true;
			}
		}
	}
	return false;
}
int main()
{
	cin>>n>>m;
	memset(h,-1,sizeof h);
	while(m--){
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);
	}
	if(spfa()) puts("Yes");
	else puts("No");
	return 0;
}

5、spfa求最短路:

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 15e4+10; 
typedef pair<int ,int>PII;
int h[N],e[N],ne[N],idx,w[N];
int n,m;
int dis[N],st[N];
void add(int a,int b,int c)
{
	e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}

int dij()
{
	memset(dis,0x3f,sizeof dis);
	dis[1] = 0;
	queue<int>q;
	q.push(1);
	st[1] = true;
	
	while(q.size()){
		int t = q.front();
		q.pop();
		st[t]  = false;
		for(int i=h[t];i!=-1;i = ne[i]){
			int j= e[i];
			if(dis[j] > dis[t] + w[i]){
				dis[j] = dis[t]+w[i];
				q.push(j);
				st[j] = true;
			}
		}
	}
	if(dis[n] == 0x3f3f3f3f) return -1;
	return dis[n];
}
int main()
{
	cin>>n>>m;
	memset(h,-1,sizeof h);
	while(m--){
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);
	}
	int t = dij();
	if(t == -1) puts("impossible");
	else cout<<t<<endl;
	return 0;
}

6、Floyd求最短路:

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 210,INF= 1e9;

int n,m,q;
int d[N][N];
int main()
{
	cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i == j) d[i][j] == 0;
			else d[i][j] = INF;
		}
	}
	while(m--){
		int a,b,w;
		scanf("%d%d%d",&a,&b,&w);
		d[a][b] = min(d[a][b],w);
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
			}
		}
	}
	while(q--){
		int a,b;
		scanf("%d%d",&a,&b);
		if(d[a][b]>INF/2) puts("impossible");
		else 
		printf("%d\n",d[a][b]);
	}
	return 0;
}

总结:这部分真的特别特别的重要,希望大家能够完全掌握,对以后的面试也有帮助的,感谢大家的观看!!!


http://www.niftyadmin.cn/n/5340600.html

相关文章

gitlab-ci相关部署踩坑及要点记录

最近在搞cicd相关的事情&#xff0c;在这个过程中遇到了一些疑惑&#xff0c;顺便记录下来&#xff0c;如果对正在有相同迷惑的同学有帮助的话&#xff0c;也是一件很好的事情。 准备工作&#xff1a; 安装gitlab&#xff0c;这个安装网上太多了&#xff0c;可以使用二进制的…

R语言批量把数值变量和因子变量的互转

#我们以rms包的lung数据集为例 library(rms) data<-lung #这里有两种方法&#xff0c; #第1是知道需要转化的变量在哪几列&#xff1b; #第2知道需要转化的变量名 str(data) #假设我们想转化inst/status/sex/三个变量的类型 #图1先看看变量类型和处于第几列 str(dat…

VUE: 处理 PDF文件

PDF.js 的技术特性 功能强大&#xff0c;内置了很多实用的 api&#xff0c;几乎可以对 PDF 文件“为所欲为”&#xff1b;兼容性超好&#xff0c;不仅支持现代浏览器&#xff0c;对于旧版本的浏览器也有很好的支持易于上手&#xff0c;官方也提供了很多代码例子。 用 PDF.js 来…

红队渗透靶机:TOPPO: 1

目录 信息收集 1、arp 2、nmap 3、nikto 4、whatweb 5、dirsearch WEB tips1 tips2 SSH登录 提权 系统信息收集 本地 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:69:c7:bf, IPv4: 192.168.110…

20.云原生之GitLab CICD实战

云原生专栏大纲 文章目录 GitLab RunnerGitLab Runner 介绍Gitlab Runner工作流程 Gitlab集成Gitlab RunnerGitLab Runner 版本选择Gitlab Runner部署docker-compose方式安装kubesphere中可视化方式安装helm方式安装 配置gitlab-runner配置gitlab-ci.ymlgitlab-ci.yml 介绍编写…

IntelliJ IDEA 如何配置git?

在IntelliJ IDEA中配置Git可以让你方便地进行版本控制、代码提交和协作开发。下面是一些简单的步骤&#xff0c;帮助你配置Git&#xff1a; 1、安装Git&#xff1a; 首先&#xff0c;确保你已经在你的计算机上安装了Git。你可以从Git官方网站&#xff08;https://git-scm.com…

React16源码: React中的completeWork中对不同类型节点处理的源码实现

completeWork 1 &#xff09;概述 在 completeUnitOfWork 当中&#xff0c;在节点是正常渲染没有任何出错的情况下会去调用 completework&#xff0c;对这个节点进行一个完成工作的一系列操作在update各种component的时候&#xff0c;执行了各种获取context相关的内容对于 com…

实现VLAN之间的路由

原理&#xff1a;路由器子接口 一个接口允许多个VLAN通过&#xff08;避免占用物理路由器接口&#xff09;。 目标 第 1 部分&#xff1a;单臂路由 第 2 部分&#xff1a;配置第三层交换机的路由端口 第 3 部分&#xff1a;带SVI的VLAN间路由 第 4 部分&#xff1a;补充知…