二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency)

news2024/11/17 21:34:22

文章目录

  • 算法模板
    • Dijkstra题目代码模板
      • 朴素dijkstra算法
      • 堆优化版dijkstra
    • 树与图的存储
      • (1) 邻接矩阵:
      • (2) 邻接表:
      • 关于e[],ne[],h[]的理解
    • 关于堆的原理与操作
  • 模板题
    • Dijkstra求最短路 I
      • 原题链接
      • 题目
      • 思路
      • 题解
    • Dijkstra求最短路 II
      • 原题链接
      • 题目
      • 思路
      • 题解
    • 1003 Emergency
      • 原题链接
      • 题目
      • 思路
      • 题解

算法模板

在这里插入图片描述

Dijkstra题目代码模板

朴素dijkstra算法

对应模板题:Dijkstra求最短路 I
时间复杂是 O(n^2+m):n 表示点数,m 表示边数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定

// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    for (int i = 0; i < n - 1; i ++ )
    {
        int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        // 用t更新其他点的距离
        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);

        st[t] = true;
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

堆优化版dijkstra

对应模板题:Dijkstra求最短路 II
时间复杂度 O(mlogn):n 表示点数,m 表示边数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

typedef pair<int, int> PII;

int n;      // 点的数量
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储所有点到1号点的距离
bool st[N];     // 存储每个点的最短距离是否已确定

// 求1号点到n号点的最短距离,如果不存在,则返回-1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, 1});      // first存储距离,second存储节点编号

    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 (dist[j] > distance + w[i])
            {
                dist[j] = distance + w[i];
                heap.push({dist[j], j});
            }
        }
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

树与图的存储

树是一种特殊的图,与图的存储方式相同。
对于无向图中的边ab,存储两条有向边a->b, b->a。
因此我们可以只考虑有向图的存储。

(1) 邻接矩阵:

g[a][b] 存储边a->b

(2) 邻接表:

https://www.acwing.com/video/21/
(1:20:00左右)

// 对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
int h[N], e[N], ne[N], idx;

// 添加一条边a->b
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

int main(){
	...
	// 初始化
	idx = 0;
	memset(h, -1, sizeof h);
	...
}

有权重时模板:

int h[N],w[N],e[N],ne[N],idx; 

void add(int a,int b,int c){
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}

关于e[],ne[],h[]的理解

在这里插入图片描述
h[N] : 表示 第 i 个节点的 第一条边的 idx
ne[M] : 表示 与 第 idx 条边 同起点 的 下一条边 的 idx
e[M] : 表示 第idx 条边的 终点

N : 节点数量
M:边的数量
i : 节点的下标索引
idx : 边的下标索引
变量初始化定义:

int h[N], e[M], ne[M], idx;

当我们加入一条边的时候:

void add(int a,int b){
     e[idx] = b;      // 记录 加入的边 的终点节点
     ne[idx] = h[a]; // h[a] 表示 节点 a 为起点的第一条边的下标,ne[idx] = h[a] 表示把 h[a] 这条边接在了 idx 这条边的后面,其实也就是把 a 节点的整条链表 接在了 idx 这条边 后面;目的就是为了下一步 把 idx 这条边 当成 a 节点的单链表的 第一条边,完成把最新的一条边插入到 链表头的操作;
     h[a] = idx++; // a节点开头的第一条边置为当前边,idx移动到下一条边
}

要注意的是邻接表插入新节点时使用的是“头插”,如图中节点2:当插入2 1时此时为2—>1, 而后插入2 4后,此时为 2—> 4 —> 1.
在这里插入图片描述

关于堆的原理与操作

二、数据结构10:堆 模板题+算法模板(堆排序,模拟堆)

模板题

Dijkstra求最短路 I

原题链接

https://www.acwing.com/problem/content/851/

题目

给定一个 n
个点 m
条边的有向图,图中可能存在重边和自环,所有边权均为正值。

请你求出 1
号点到 n
号点的最短距离,如果无法从 1
号点走到 n
号点,则输出 −1

输入格式
第一行包含整数 n
和 m

接下来 m
行每行包含三个整数 x,y,z
,表示存在一条从点 x
到点 y
的有向边,边长为 z

输出格式
输出一个整数,表示 1
号点到 n
号点的最短距离。

如果路径不存在,则输出 −1

数据范围
1≤n≤500
,
1≤m≤105
,
图中涉及边长均不超过10000。

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3

思路

在这里插入图片描述
在这里插入图片描述

题解

#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
const int N = 510;
const int M = 1e5 + 10;
int dist[N]; // 存各点与1号点的最短距离 
bool st[N]; // 存各点是否已被 处理为最短距离点 判断 (当前已确定最短距离的点) 
int g[N][N];
int n,m,t;

int dijkstra(){

	memset(dist,0x3f,sizeof dist);
	dist[1] = 0;
	for(int i = 0;i<n;i++){
		t = -1; //	t: 不在 当前已确定最短距离的点 中的距离最短的点 初始化为-1 
		for(int j = 1;j<=n;j++){
			if(!st[j] && (t == -1 || dist[t] > dist[j])){
				t = j;
			}
		}
		
		st[t] = true;
		for(int j=1;j<=n;j++){
			dist[j] = min(dist[j],dist[t] + g[t][j]); //用(1到t+t到j)的长度与(1到j)的长度进行对比更新 
		}
		
	}
	if(dist[n] == 0x3f3f3f3f) return -1;
	else return dist[n];
}
int main(){
	cin>>n>>m;
	memset(g,0x3f,sizeof g);
	for(int i=0;i<m;i++){
		int x,y,z;
		cin>>x>>y>>z;
		g[x][y] = min(g[x][y],z);
		
	}	
	
	int res = dijkstra();
	
	printf("%d",res);
	
	return 0;
	
	
}

Dijkstra求最短路 II

原题链接

https://www.acwing.com/problem/content/852/

题目

给定一个 n
个点 m
条边的有向图,图中可能存在重边和自环,所有边权均为非负值。

请你求出 1
号点到 n
号点的最短距离,如果无法从 1
号点走到 n
号点,则输出 −1

输入格式
第一行包含整数 n
和 m

接下来 m
行每行包含三个整数 x,y,z
,表示存在一条从点 x
到点 y
的有向边,边长为 z

输出格式
输出一个整数,表示 1
号点到 n
号点的最短距离。

如果路径不存在,则输出 −1

数据范围
1≤n,m≤1.5×105
,
图中涉及边长均不小于 0
,且不超过 10000

数据保证:如果最短路存在,则最短路的长度不超过 109

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3

思路

使用堆优化,选择用stl中的priority_queue进行操作
在这里插入图片描述
关于st[N]数组 处理冗余部分
https://www.acwing.com/solution/content/167860/

题解

#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int M = 2e5 + 10;
typedef pair<int,int> PII;
int dist[N]; // 存各点与1号点的最短距离 
bool st[N]; // 存各点是否已被 处理为最短距离点 判断 (当前已确定最短距离的点) 
//int g[N][N];
//堆优化中,由于为稀疏图,因此使用邻接表进行存储
int h[N],w[N],e[N],ne[N],idx; 

int n,m,t;

//邻接表插入处理 
void add(int a,int b,int c){
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}

int dijkstra(){

	memset(dist,0x3f,sizeof dist);
	dist[1] = 0;
	
//	堆优化版dijkstra
	priority_queue<PII,vector<PII>,greater<PII>> heap;
	heap.push({0,1}); // {距离,编号}编号为1的点距离为0,表示1到1的距离为0 
	
	while(heap.size()){
		auto t = heap.top();
		heap.pop();
		
		int ver = t.second, distance = t.first; // distance :结点1到结点ver的距离
		if(st[ver]) continue;  // 冗余的话跳过
		st[ver] = true;
		
		for(int i=h[ver]; i!=-1; i=ne[i]){ // 邻接表遍历,从h[ver]开始遍历可达的所有结点
			int j = e[i];
			
//			w[i]:结点ver到结点j的距离
			if(dist[j]>distance + w[i]){ // 1--->i的距离 和 1--->ver--->i的距离相比
				dist[j] = distance + w[i]; 
				heap.push({dist[j],j});
			}
		} 
	}
	
	if(dist[n] == 0x3f3f3f3f) return -1;
	else return dist[n];
}
int main(){
	cin>>n>>m;
//	memset(g,0x3f,sizeof g);
	memset(h,-1,sizeof h);;
	for(int i=0;i<m;i++){
		int x,y,z;
		cin>>x>>y>>z;
		add(x,y,z);
		
	}	
	
	int res = dijkstra();
	
	printf("%d",res);
	
	return 0;
	
	
}

1003 Emergency

原题链接

原题链接

题目

题目大意:n个城市m条路,每个城市有救援小组,所有的边的边权已知。给定起点和终点,求从起点到终点的最短路径条数以及最短路径上的救援小组数目之和。如果有多条就输出点权(城市救援小组数目)最大的那个

思路

用一遍Dijkstra算法,救援小组个数相当于点权,用Dijkstra求边权最小的最短路径的条数,以及这些最短路径中点权最大的值
dis[i]表示从出发点到i结点最短路径的路径长度,
num[i]表示从出发点到i结点最短路径的条数,
w[i]表示从出发点到i点救援队的数目之和
当判定dis[u] + e[u][v] < dis[v]的时候,
不仅仅要更新dis[v],还要更新num[v] = num[u], w[v] = weight[v] + w[u];
如果dis[u] + e[u][v] == dis[v],还要更新num[v] += num[u],而且判断一下是否权重w[v]更小,如果更小了就更新w[v] = weight[v] + w[u];

题解

基于上述朴素版dijkstra进行改进,

#include <bits/stdc++.h>
using namespace std;
//题目大意:n个城市m条路,每个城市有救援小组,所有的边的边权已知。给定起点和终点,求从起点到终点的最短路径条数以及最短路径上的救援小组数目之和。如果有多条就输出点权(城市救援小组数目)最大的那个~
//
//分析:用一遍Dijkstra算法~救援小组个数相当于点权,用Dijkstra求边权最小的最短路径的条数,以及这些最短路径中点权最大的值~dis[i]表示从出发点到i结点最短路径的路径长度,num[i]表示从出发点到i结点最短路径的条数,w[i]表示从出发点到i点救援队的数目之和~当判定dis[u] + e[u][v] < dis[v]的时候,不仅仅要更新dis[v],还要更新num[v] = num[u], w[v] = weight[v] + w[u]; 如果dis[u] + e[u][v] == dis[v],还要更新num[v] += num[u],而且判断一下是否权重w[v]更小,如果更小了就更新w[v] = weight[v] + w[u]; 

const int N = 510;
int g[N][N];
int c1,c2;
int dist[N]; //dist[i]表示从出发点到i结点最短路径的路径长度
int weight[N]; //每个城市救援队数量
int w[N]; //w[i]表示从出发点到i点救援队的数目之和
bool st[N]; 
int num[N]; //num[i]表示从出发点到i结点最短路径的条数

int n,m;

void dij(){
	w[c1] = weight[c1];
	memset(dist,0x3f,sizeof dist);
	dist[c1] = 0;
	num[c1] = 1;
	int t;
	for(int i=0;i<n;i++){
		t = -1;
		for(int j=0;j<n;j++){
			if(!st[j] && (t==-1 || dist[t] >dist[j]) )
			{
				t = j;
			}
		}
		st[t] = true;
		for(int j=0;j<n;j++){
//			dist[j] = min(dist[j],dist[t] + g[t][j]);
			if(dist[j]>dist[t]+g[t][j]){ //当判定dis[u] + e[u][v] < dis[v]的时候,不仅仅要更新dis[v],还要更新num[v] = num[u], w[v] = weight[v] + w[u]; 
				dist[j] = dist[t]+g[t][j];
				num[j] = num[t];
				w[j] = w[t] + weight[j];  
//				cout<<t<<" "<<w[t]<<endl;
//				w[j]+=weight[t];
			}
			else if(dist[j]==dist[t]+g[t][j]){ //如果dis[u] + e[u][v] == dis[v],还要更新num[v] += num[u],而且判断一下是否权重w[v]更小,如果更小了就更新w[v] = weight[v] + w[u]; 
				num[j] = num[t]+num[j];
				if(w[t]+weight[j] > w[j]){
					w[j] = w[t] + weight[j];
				}
			}	
		}
	}
	
//	return w[c2];	
}
int main(){
	cin>>n>>m>>c1>>c2;
	
	for(int i=0;i<n;i++){
		int t;
		cin>>t;
		weight[i] = t;
	}
	memset(g,0x3f,sizeof g); // 赋值无穷大 
	
	for(int i=0;i<m;i++){
		int x,y,z;
		cin>>x>>y>>z;
		g[x][y] = g[y][x] = z; // 无向图!所以存双向信息 
	}
	
	dij();
	
	cout<<num[c2]<<" "<<w[c2];
} 

参考链接:1003. Emergency (25)-PAT甲级真题(Dijkstra算法)

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

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

相关文章

cpolar内网穿透可应用于哪些场景?

前言 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐的一位博主。 &#x1f4d7;本文收录于恒川的日常汇报系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏C语言初…

RGB颜色值与十六进制颜色码对照表(超详细)

(꒪ꇴ꒪ ),hello我是祐言博客主页&#xff1a;C语言基础,Linux基础,软件配置领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff01;送给读者的一句鸡汤&#x1f914;&#xff1a;集中起来的意志可以击穿顽石!作者水平很有限&#xff0c;如果发现错误&#x…

VGG卷积神经网络-笔记

VGG卷积神经网络-笔记 VGG是当前最流行的CNN模型之一&#xff0c; 2014年由Simonyan和Zisserman提出&#xff0c; 其命名来源于论文作者所在的实验室Visual Geometry Group。 测试结果为&#xff1a; 通过运行结果可以发现&#xff0c;在眼疾筛查数据集iChallenge-PM上使用VGG…

maven发布到中央仓库

创建账号 https://issues.sonatype.org 【第二步】登录申请新项目 右上角点击Create&#xff0c;Project选择第一项&#xff0c;有的时候带不出来第二个New Project&#xff0c;可以再选一次Project的选项。

warning Replace `‘vue‘` with `“vue“;`

warning Replace vue with "vue"; 如果报以上错误 不要怀疑直接找 .eslintrc 元凶就是他 方法一 在配置关闭eslint语法检测 在vite.config.ts文件中 方法二 适用于项目中不得不依赖 eslint 进行配置结尾换行符&#xff0c;那么就会直接在开发环境中进行验证。…

面向对象程序三大特性一:多态(超详细)

目录 1.重写 1.1基本语法规则 1.2规则深化 1.3重写与重载的区别 2.向上转型 2.1简单介绍 2.3向上转型的作用 3.向下转型 3.1介绍 3.2instanceof 基本介绍 4.多态 4.1多态实现条件 4.2避免在构造方法中调用重写的方法 1.重写 重写 (override) &#xff1a;也称为覆…

数据库导出Excel格式的表结构

数据库导出Excel格式的表结构 你是否遇到到导出数据库里面的表结构&#xff0c;包含字段名称、类型、长度、小数、默认值、字段描述之类的需求&#xff1b;当我们去navcat里面找时发现没有&#xff0c;因为navcat没有提供这一功能&#xff0c;他只可以导出表结构的sql&#xff…

一百四十、海豚调度器——海豚删除无法直接删除的工作流

一、目的 海豚调度器有时会遇到无法直接删除的工作流&#xff0c;一旦直接删除就会报错&#xff1a; 批量删除工作流实例错误: 218 二、解决方法 (一)打开MySQL的dolphinscheduler数据库的表t_ds_process_definition &#xff08;二&#xff09;根据报错的工作流名称hive_ba…

上海亚商投顾:沪指震荡微涨 金融、地产午后大幅走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数早盘震荡&#xff0c;午后集体拉升反弹&#xff0c;创业板指涨超1%。券商等大金融板块午后再度走强&#…

C语言多级指针

#include "stdio.h" #include <stdlib.h>int main() {int a 10;//*p int a int *pint* p &a;int** q &p;//int** q int *(*q) int *(q) a//int**q int*(*q) int*(&a) int*&a aint*** k &q;//分析&#xff1a;首先k是个变量&…

HDFS介绍

目录 ​编辑 一、HDFS基础 1.1 概述 1.2 HDFS的设计目标 1.2.1 硬件故障 1.2.2 流式数据访问 1.2.3 超大数据集 1.2.4 简单的一致性模型 1.2.5 移动计算而不是移动数据 1.2.6 跨异构硬件和软件平台的可移植性 1.3 基础概念 1.3.1 块&#xff08;Block&#xff09; 1.3.2 复制…

【智慧校园】智慧班牌解决方案

【智慧校园】智慧班牌全套源码 智慧校园saas云平台系统 前后端分离架构 1、使用springboot框架Javavue2 2、数据库MySQL5.7 3、移动端小程序使用小程序原生语言开发 4、电子班牌固件安卓7.1&#xff1b;使用Java Android原生 5、elmentui &#xff0c;Quartz&#xff0c;jpa&a…

MyBatis的动态SQL语句

文章目录 前言LocalDate数据库代码po 包 ifwhere 标签 查trim 标签 增set 标签 改foreach 标签 删 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 查询条件是动态的 MyBatis的动态SQL语句是指在运行时根据不同条件选择不同的SQL语句执行。 这些条件可…

华为OD机试真题 Java 实现【阿里巴巴找黄金宝箱(IV)】【2023 B卷 100分】,附详细解题思路

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 七、复杂度分析1、时间复杂度2、空间复杂度 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAV…

CAD随机球体颗粒过渡区3D插件

插件介绍 CAD随机球体颗粒&过渡区3D插件可用于在AutoCAD软件内生成随机分布的球体及球体外侧过渡区部件&#xff0c;适用于科研绘图、有限元建模如混凝土细观、颗粒增强复合材料、随机三维骨料及过渡区等方面的应用。 插件可指定的参数有模型的长、宽、高&#xff1b;球…

批处理文件的@echo off是什么意思?

echo off 关闭回显 echo on 打开回显 echo off并不是DOS程序中的&#xff0c; 而是DOS批处理中的。 当年的DOS&#xff0c;所有操作都用键盘命令来完成&#xff0c; 当你每次都要输入相同的命令时&#xff0c; 可以把这么多命令存为一个批处理&#xff0c; 从此以后&#xff…

MybatisPlus的QueryWrapper方法解释

QueryWrapper继承AbstractLambdaWrapper 继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件以及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取. 一些用法 常规 queryWrapper.lt&#xff08;&#xff09;——小于queryWrapper.le…

揭开接口自动化测试的神秘面纱,从入门到高级实战

接口测试背景和必要性 接口测试是测试系统组件间接口&#xff08;API&#xff09;的一种测试&#xff0c;主要用于检测内部与外部系统、内部子系统之间的交互质量&#xff0c;其测试重点是检查数据交换、传递的准确性&#xff0c;控制和交互管理过程&#xff0c;以及系统间相互…

vue3引用Font-Awesome字体图标库

环境&#xff1a;vue3tsviteelement plus 介绍&#xff1a;这里安装引用的是Font-Awesome 6.x 版本&#xff0c;有专业版&#xff08;付费&#xff09;&#xff0c;这里只介绍免费版字体使用方法 一、安装 1.使用npm安装&#xff0c;终端打开项目目录或者命令行cd到目录文件夹…

QMessageBox、QColorDialog、按钮汉化显示

QMessageBox、QColorDialog、按钮汉化显示 版本&#xff1a;Qt5.9.9 环境&#xff1a;QtCretator MinGW 在Qt源码目录下找到qt_zh_CN.ts复制一份到工程目录&#xff0c;该文件在&#xff1a;G:\install\Qt\Qt5.9.9\5.9.9\Src\qttranslations\translations。 打开qt_zh_CN.ts文…