蓝桥杯上岸必背!!!(第七期 最短路算法)

news2024/11/26 13:50:58

第七期:最短路算法🔥 🔥 🔥

蓝桥杯热门考点模板总结来啦✨

你绝绝绝绝绝绝对不能错过的常考最短路算法模板 💥

❗️ ❗️ ❗️

大家好 我是寸铁✨

还没背熟模板的伙伴们背起来 💪 💪 💪

祝大家4月8号蓝桥杯上岸 ☀️

不清楚蓝桥杯考什么的点点下方👇

考点秘籍

想背纯享模版的伙伴们点点下方👇

蓝桥杯省一你一定不能错过的模板大全(第一期)

蓝桥杯省一你一定不能错过的模板大全(第二期)

想背注释模版的伙伴们点点下方👇

蓝桥杯必背第一期

蓝桥杯必背第二期

往期精彩回顾

蓝桥杯上岸每日N题 第一期(一)!!!

蓝桥杯上岸每日N题第一期(二)!!!

蓝桥杯上岸每日N题第一期(三)!!!

蓝桥杯上岸每日N题第二期(一)!!!

蓝桥杯上岸每日N题第三期(一)!!!

操作系统期末题库 第九期(完结)

LeetCode Hot100 刷题(第三期)

idea创建SpringBoot项目报错解决方案

数据库SQL语句(期末冲刺)

想看JavaB组填空题的伙伴们点点下方 👇

填空题

竞赛干货

算法竞赛字符串常用操作大全

蓝桥杯上岸必刷!!!(模拟/枚举专题)

蓝桥杯上岸必背!!! (第三期 DP)

蓝桥杯上岸必背!!!(第四期DFS)

蓝桥杯上岸必背!!!(第五期BFS)

蓝桥杯上岸必背!!!(第六期树与图的遍历)

最短路是蓝桥杯的热门考点,距离省赛仅剩4天,干就完事了 ❗️

下面让我们开始刷起来 ❗️ ❗️ ❗️

问题:请你计算通往蓝桥杯的最短路 ❓

提示:跟着寸铁背模板💪 💪 💪

答案:Accepted

SPFA求最短路

(正负权均可,存在被卡的风险,以前算竞最常背的模板,保险起见可以再背一个Dijkstra())

做法

用队列来维护搜索的顺序,一层一层往下搜,相当于BFS
每次用当前搜的这一轮的最短距离去更新下一轮的最短距离

注意

初始化dist数组为INF,这样做的目的是便于去判断是否走到n存在最短路
st[]数组存的是当前在队列中的元素,所以在每次入队时,可以将元素置为true,表示在队列中。
出队时,再将元素置为false,表示不在队列中,这样就避免了更新重复元素的最短路

spfa模板

import java.util.*;
public class Main{
    static int N=100010,n,m,idx,INF=0x3f3f3f3f;
    static int []h=new int[N],e=new int[N],ne=new int[N],w=new int[N];
    static int []q=new int[N];
    static int []dist=new int[N];
    static boolean []st=new boolean[N];
    public static void add(int a,int b,int c){
        e[idx]=b;
        w[idx]=c;
        ne[idx]=h[a];
        h[a]=idx++;
    }
    public static void spfa(){
        Queue<Integer>q=new LinkedList<>();
        Arrays.fill(dist,INF);
        q.offer(1);
        dist[1]=0;
        st[1]=true;
        while(!q.isEmpty()) {
        	int t=q.poll();
        	st[t]=false;
        	//表示不在队列中
        	//避免重复元素的查找
        	for(int i=h[t];i!=-1;i=ne[i]) {
        		int j=e[i];
        		if(dist[j]>dist[t]+w[i]) {
        			dist[j]=dist[t]+w[i];
        			//满足这个条件的才需要入队
                   //写在外面就会将不满足这个条件的都入队
        			if(!st[j]) {
        				q.offer(j);
        				st[j]=true;
        				//表示在队列中
        				
        			}
        		}
        		
        	}
        	
        }
        if(dist[n]==INF)System.out.println("impossible");
        else System.out.println(dist[n]);
        
    }
    
    public static void main(String []args){
        Scanner in = new Scanner(System.in);
        n=in.nextInt();
        m=in.nextInt();
        Arrays.fill(h, -1);
        while(m-->0) {
        	int a=in.nextInt();
        	int b=in.nextInt();
        	int c=in.nextInt();
        	add(a, b, c);
        }
        spfa();
    }
    
    
}

Dijkstra朴素版

Dijkstra求最短路I

题目描述

对于边的权值不为1且边权值均为正值求最短距离的题目
采用Dijkstra算法求最短路
在这里插入图片描述
再看数据范围500*10的5次方n*m级别,对应的是稠密图,采用Dijstra朴素做法处理。

分析

做法

由于采用的是Dijkstra朴素法,且是稠密图,所以使用邻接矩阵存储边。
循环n次,找到第1号点到n个点的距离
(1)第一次迭代,找到当前循环的最小距离的点,将其进行标记为true
(2)再进行第二次迭代,更新比较dist[j]和当前最小距离的点到j的距离(dist[t]+g[t][j])的最小值。
循环n次,可以确保找到每轮循环的最小距离的点。
注:如果最后存在有点的最小距离还是max,也就是说没有给出从1->n号点的边或者是从t到第n号点的边,使得dist[n]的距离仍为max,返回-1即可

模拟

在这里插入图片描述

注:像自环和重边的情况,自环自己指向自己,在求最短距离的过程中,不影响求最短路,会被自动忽略掉。
重边的情况,我们只需要在主方法中,选取g[a][b]的最短边即可。

代码

import java.util.*;
public class Main{
	static int N=510,n,m,max=0x3f3f3f3f;
	static int [][]g=new int[N][N];
	static int []dist=new int[N];
	static  boolean []st=new boolean[N];
	public static int dijkstra() {
		Arrays.fill(dist, max);
		//将dist数组里每个点的距离初始化为max
		dist[1]=0;
   //将1号点的距离初始化为0,不能初始化为1,初始化为1是自环,后续的最短路径的点便查找不到
		for(int i=0;i<n;i++) {
		  //因为最短路径的寻找不是直接比较即得
            //需要走各个点到点的距离即dist[t]+g[t][j]再和dist[j]比较。
            //所以需要每次寻找最短距离的点,再去更新dist[t]+g[t][j]
            //循环一轮后,得到一个点的最短距离,循环n轮后,得到n个点的最短距离。
            //循环1次,确定一个点的最短距离。循环n次,确定n个点的最短距离。
            //这样便求出每个点到起点的最短距离
			
			int t=-1;//过渡变量
			for(int j=1;j<=n;j++) {
		//第一轮迭代,寻找最短路径的点,并在第2轮迭代中用这个点去更新其他点的最短路径
				
				if(!st[j]&&(t==-1||dist[j]<dist[t]) ){
					//如1号点未被标记过,就更新1号点到1号点的距离,即初始化的max
					//进入迭代,更新1号点到各个点的距离,寻找当前最短路径的点。
					t=j;
				}
			}
			st[t]=true;//标记t为最短路径的点
		
		for(int j=1;j<=n;j++) {//第二轮迭代,迭代每个点的最短距离
			dist[j]=Math.min(dist[j], dist[t]+g[t][j]);
     //从当前最短距离的点到j号点的距离与从最短距离点到j号点的距离进行比较,求最小值。
		}
		}
		if(dist[n]==max)return -1;
		//没有给出从1-n号点的边或者是从t到n号点的边,使得dist[n]的距离仍为max,返回-1。
		else return dist[n];//返回从1号点到n号点的距离
		
	}
	public static void main(String []args) {
		Scanner in = new Scanner(System.in);
		n=in.nextInt();
		m=in.nextInt();
		for(int i=1;i<=n;i++) {
		    //初始化每一个点到其他点的距离均为max
			Arrays.fill(g[i], max);
		}
		while(m-->0) {
			int a=in.nextInt();
			int b=in.nextInt();
			int c=in.nextInt();
			g[a][b]=Math.min(g[a][b], c);
			//出现重边情况,取边长最短的那条边
		}
	System.out.println(dijkstra());
	}
}

Dijkstra堆优化版

Dijkstra求最短路 II

题目分析

运用优先队列(堆)+邻接表
先让第一个点进堆,再让它出队,去找到当前最小距离,入堆,堆顶的位置为当前的最小距离。
再让堆顶的位置出堆,标记该点已出堆过,不能重复出堆,再用它去更新其它的点的最小距离。
再将每一次循环后的最小距离的点入堆,更新最短距离,出堆,再去更新最小距离的点,再让最小距离的点入堆,重复这个过程,直至每个点都被标记过。

过程分析

整个过程类似于BFS,用当前最小距离的点去更新它的邻接节点的距离,再入堆,再出堆,又用出堆的最小距离的点去更新他的邻接节点,一层一层往下搜,直至最小距离的点都被标记过。

时间复杂度分析

_O(n*n)--> O(n*logn)_

标记的作用

堆顶是整个小根堆的最小距离,更新过一次后,在陆续的循环中,堆顶是不会被更新的。
比堆顶大的最小距离的点会依次入堆,会被安放在堆下面的位置,所以,需要打上标记,防止重复出队。
再依次出队每一轮循环的最短距离去更新其它点的最小距离。

模拟

在这里插入图片描述

注:绿星表示的是打上标记,每次入堆的点出堆后都会打上标记。

代码

import java.io.*;
import java.util.*;
public class Main{
    static int N=150010,idx,n,m;
    static int dist[]=new int[N];
    static int h[]=new int[N];
    static int e[]=new int[N];
    static int ne[]=new int[N];
    static int w[]=new int[N];
    static boolean st[]=new boolean[N];
    static int inf=0x3f3f3f3f;
    public static void add(int a,int b,int c){
        e[idx]=b;
        w[idx]=c;//赋权
        ne[idx]=h[a];
        h[a]=idx;
        idx++;
    }
    public static int dijkstra(){
        PriorityQueue<PIIs>queue=new PriorityQueue<PIIs>();//优先队列,相当于堆
        Arrays.fill(dist,inf);//初始化每个dist的距离为inf
        dist[1]=0;//初始化1这个点的距离为0
        queue.add(new PIIs(0,1));//PIIs类型加入堆中
        while(!queue.isEmpty()){
            PIIs p = queue.poll();//出队
    //这里出队的话,主要是堆中的堆顶是堆中最小的,依次比它较小的元素在堆顶的下面。
    //由于堆顶不会被更新,所以需要出队来依次遍历每轮循环的最小值。
            int t=p.getSecond();//获得这个点
            int distance=p.getFirst();//获得这个点的距离
            if(st[t])continue;//如果被标记过,就从头开始循环
            st[t]=true;//标记当前为最小值的点
            for(int i=h[t];i!=-1;i=ne[i]){
                int j=e[i];//获得邻接节点
                if(dist[j]>distance+w[i]){//更新邻接节点的最小值,类似于bfs一层一层往下搜
                    dist[j]=distance+w[i];//更新为当前点的最小值
                    queue.add(new PIIs(dist[j],j));//入堆
                }
                
            }
            
            
        }
        if(dist[n]==inf)return -1;//如果dist[n]=inf,返回-1
        else return dist[n];//返回到n号点的距离
    }
    
    public static void main(String []args) throws IOException {
    	BufferedReader re=new BufferedReader(new InputStreamReader(System.in));
    	String []str1=re.readLine().split(" ");
    	n=Integer.parseInt(str1[0]);
    	m=Integer.parseInt(str1[1]);
       Arrays.fill(h, -1);
       while(m-->0) {
    	   String str2[]=re.readLine().split(" ");
    	   int a=Integer.parseInt(str2[0]);
    	   int b=Integer.parseInt(str2[1]);
    	   int c=Integer.parseInt(str2[2]);
    	   add(a,b,c);
       }
       System.out.println(dijkstra());
       
       
       
    }
    
    
}
class PIIs implements Comparable<PIIs>{
	private int first;
	private int second;
	public int getFirst() {
		return this.first;
	}
	public int getSecond() {
		return this.second;
	}
	public PIIs(int first,int second) {
		this.first=first;
		this.second=second;
	}
	public int compareTo(PIIs o) {
		return Integer.compare(first, o.first);
	}
}

Floyd求最短路

Floyd求最短路

不同于前面的最短路,属于单元汇,求的是1号点到各个点的最短路。
Floyd求的是**x号点到y号点的最短路,属于多元汇**最短路问题。
dist[i][j]存的是i号点到j号点的最短距离
将邻接矩阵转换为最短距离矩阵,查表即可。

实现代码

3重for循环实现

for(int k=1;k<=n;k++){
//先循环k,i,j顺序可颠倒。
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);
        }
    }
}

其本质是一个动态规划问题:

dist[k,i,j]=dist[k-1,i,k]+dist[k-1,k,j];

理解:
 i点到j点经过1到k条边的距离
=i点到k点经过1到k-1条边的距离+k点到j点经过1到k-1条边的距离
由于两段距离都经过1到k-1个点,类似于dp优化,计算时保存的是上一层的值,所以可以将这一重给省略掉。

变为二维:
dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);

时间复杂度

3层for循环:每层循环走n个点
O(n^3)

代码

import java.util.*;
public class Main{
    static int n,m,q;
    static int INF=0x3f3f3f3f;
    static int N=210;
    static int dist[][]=new int[N][N];
    public static void floyd(){
        for(int k=1;k<=n;k++){
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);
                }
            }
        }
    }
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        q=sc.nextInt();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i==j)dist[i][j]=0;
        //不存在负权回路,处理自环,自己指向自己默认为0
        //不影响更新其他点的距离
                else{
                dist[i][j]=INF;
                }
            }
        }
        while(m-->0){
            int a=sc.nextInt();
            int b=sc.nextInt();
            int w=sc.nextInt();
            dist[a][b]=Math.min(dist[a][b],w);
            //处理重边,保留最小的边权即可
        }
        floyd();
        while(q-->0){
            int a=sc.nextInt();
            int b=sc.nextInt();
            if(dist[a][b]>INF/2)System.out.println("impossible");
            //边权为负,存在某些点到点的距离比INF要小一些
            //需要大于INF/2
            else System.out.println(dist[a][b]);
        }
    }
}

✨ ✨ ✨
看到这里,不妨点个关注 💖

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/794192.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot整合JavaMail

SpringBoot整合JavaMail 简单使用-发送简单邮件 介绍协议 导入坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>添加配置 spring:mail:host: smtp.qq.co…

JVM系统优化实践(23):GC生产环境案例(6)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 在互联网大厂中&#xff0c;对每天亿级流量的日志进行清洗、整理是非常常见的工作。在某个系统中&#xff0c;需要对用户的访问日志做脱敏处理&#xff0c;也就是清洗掉姓名…

day41-Verify Account Ui(短信验证码小格子输入效果)

50 天学习 50 个项目 - HTMLCSS and JavaScript day41-Verify Account Ui&#xff08;短信验证码小格子输入效果&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name&qu…

Shell脚本实战——对MySQL进行分库分表备份

一、查看当前数据库以及数据表 如何除去Datebase标题字样以及系统自带的数据库呢&#xff1f;可以使用以下命令 mysql -uroot -p#BenJM123 -e show databases -N | egrep -v "information_schema|mysql|performance_schema|sys"剩下的两个就是用户自己创建的表啦&am…

分享一个JSON插件

文章目录 知识回顾使用方法 知识回顾 看官们&#xff0c;最近在使用Flutter做网络相关的操作&#xff0c;主要是Http请求操作&#xff0c;请求结果基本上都是JSON格式&#xff0c;因此需要把JSON格式转换成Dart语法的数据模型。如果手动编写的话会占用时间而且容易出错。因此&…

UCDOS和WPS推动计算机领域的汉字化发展,中文编程该谁力扛大旗?

你还记得UCDOS吗&#xff1f; 从DOS时代过来的人&#xff0c;还知道UCDOS的&#xff0c;现在可能已经是中年人了&#xff01; 当时&#xff0c;鲍岳桥的UCDOS可以称得上是中国的国产操作系统。 在Windows还没来得及进入中国市场时&#xff0c;UCDOS可以说是走向了巅峰时刻&a…

【分库分表】分库分表常见问题和解决方案

文章目录 前言MySQL出现的性能问题Mysql常见的优化手段大数据表优化方案详解分库分表垂直拆分单库垂直分表多库垂直分表 水平拆分单库水平分表多库水平分表常见的水平分表策略哈希取模分片hash取模的问题一致性hash算法按照范围分片 分库分表实战根据uid进行水平分表如何实现全…

lambda表达式的进阶过程

文章目录 什么是Lambda表达式简述Lambda表达式的优点语法格式 函数式接口定义常见的函数式接口汇总 Lambda的演化过程lambda表达式简化 总结 什么是Lambda表达式 简述 Lambda表达式是JAVA8中提供的一种新的特性&#xff0c;是一个匿名函数方法。可以把Lambda表达式理解为一段…

关于uniapp中的日历组件uni-calendar中的小红点

关于uniapp中的日历组件uni-calendar中的小红点 如果你使用过uni-calendar组件&#xff0c;可能你觉得这个小红点有点碍眼&#xff0c;但是官方给定的日历组件uni-calendar中如果你想要在某一天上添加一些信息例如:价格&#xff0c;签到&#xff0c;打卡之类&#xff0c;只要标…

【PWN · ret2text | 伪rand()】[HDCTF 2023]pwnner

伪随机数以及ctypes库的初步接触 目录 前言 一、题目 二、解题思路 三、exp 总结 前言 一道简单的ret2text&#xff0c;加上一些伪随机的知识&#xff0c;对于本蒟蒻萌新来说&#xff0c;比较新&#xff0c;值得记录。 一、题目 栈溢出保护、PIE保护都没有开。反汇编后…

servlet银行储蓄管理系统java存取转账交易 jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 servlet银行储蓄管理系统 系统有1权限&#xff1a;管…

python与深度学习(四):ANN和fashion_mnist二

目录 1. 说明2. fashion_mnist的ANN模型测试2.1 导入相关库2.2 加载数据和模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章训练的模型进行测…

Guitar Pro有没有免费的?

Guitar Pro是一款功能强大的吉他谱编辑软件&#xff0c;它为音乐创作者和乐手提供了极大的便利。但是&#xff0c;许多人对于Guitar Pro是否有免费版本&#xff0c;问题存在疑虑。下面我们就来详细介绍Guitar Pro有没有免费的内容吧&#xff01; 一、Guitar Pro有没有免费的 …

音视频——视频流H264编码格式

1 H264介绍 我们了解了什么是宏快&#xff0c;宏快作为压缩视频的最小的一部分&#xff0c;需要被组织&#xff0c;然后在网络之间做相互传输。 H264更深层次 —》宏块 太浅了 ​ 如果单纯的用宏快来发送数据是杂乱无章的&#xff0c;就好像在没有集装箱 出现之前&#xff0c;…

MultipartFile类型接收上传文件报出的UncheckedIOException以及删除tomcat临时文件失败源码探索

1、描述异常背景&#xff1a; 因为需要分析数据&#xff0c;待处理excel文件的数据行数太大&#xff0c;手动太累&#xff0c;花半小时写了一个定制的数据入库工具&#xff0c;改成了通用的&#xff0c;整个项目中的万级别数据都在工具上分析&#xff0c;写SQL进行分析&#x…

Rust vs Go:常用语法对比(十)

题图来自 Rust vs. Golang: Which One is Better?[1] 182. Quine program Output the source of the program. 输出程序的源代码 package mainimport "fmt"func main() { fmt.Printf("%s%c%s%c\n", s, 0x60, s, 0x60)}var s package mainimport "fm…

【C语言】嵌入式C语言项目管理利器:深入理解Makefile的应用与实践

目录 一、makedile的概述 1、案例引入 2、makefile 3、Makefile优点 二、makefile的语法规则 1、语法规则 2、简单实战 三、makefile的变量 1、自定义变量 2、系统环境变量 3、预定义变量 4、高级makefile 一、makedile的概述 1、案例引入 gcc a.c b.c c.c ‐o …

Error: Please select Android SDK解决方案(仅供参考)

一、问题描述 今天开始正式接触项目的工作内容&#xff0c;然后从组里的代码仓库里git clone了一份Android Studio项目下来。下好了以后我使用Android Studio打开这个项目&#xff0c;但在尝试编译运行的时候遇到了很多错误。例如&#xff0c;开发环境界面上面用于编译的小锤子…

【MySQL】基本查询(插入查询结果、聚合函数、分组查询)

目录 一、插入查询结果二、聚合函数三、分组查询&#xff08;group by & having&#xff09;四、SQL查询的执行顺序五、OJ练习 一、插入查询结果 语法&#xff1a; INSERT INTO table_name [(column [, column ...])] SELECT ...案例&#xff1a;删除表中重复数据 --创建…

ARM汇编中类似c语言中宏定义的使用

—# 一、是什么&#xff1f; .equ xxx,xxx 类似c语言中#define xxx xxxx ## 1.操作例子 代码如下&#xff08;示例&#xff09;&#xff1a; .equ bss_start,0x2000 .equ bss_end,0x20000x100 .global _start _start:ldr r0,bss_startldr r1,bss_end