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

文章目录

  • 算法模板
    • 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算法)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

搭建自己的Git服务器

环境 服务端&#xff1a;Ubuntu 22.04 客户端&#xff1a;Win11_x64 前提条件&#xff1a;需要确保在Windows机器上能够ping通Ubuntu服务器, 并且服务端与客户端均已安装了Git软件 服务端上的配置操作 以Ubuntu服务器作为Git服务端的运行环境&#xff0c;并方便后期免密推…

aws的EC2云服务器自己操作记录

亚马逊官网有免费试用1年的服务器 以下内容参考 1. 启动生成实例 1.1 创建实例时需要生成 使用的默认的 Debian 和 一个.pem后缀的秘钥 1.2 网上下一个Mobaxterm ,实例名是公有 IPv4 DNS 地址 ,使用SSH连接,登录名是admin 1.3 登录进去后 输入用户名 admin 后进去,sudo …

聊聊我的故事-悲惨的童年

目录 前言一、介绍二、17年回顾1.出生2.上幼儿园3.上小学4.上初中 高中总结 前言 本人是06年生的&#xff0c;快18了&#xff0c; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、介绍 本人已经17了&#xff0c;在这17年过的很悲惨&#xff0c;也…

QT--day4(定时器事件、鼠标事件、键盘事件、绘制事件、实现画板、QT实现TCP服务器)

QT实现tcpf服务器代码&#xff1a;&#xff08;源文件&#xff09; #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//给服务器指针实例化空间server new QTc…

命令模式——请求发送者与接收者解耦

1、简介 1.1、概述 在软件开发中&#xff0c;经常需要向某些对象发送请求&#xff08;调用其中的某个或某些方法&#xff09;&#xff0c;但是并不知道请求的接收者是谁&#xff0c;也不知道被请求的操作是哪个。此时&#xff0c;特别希望能够以一种松耦合的方式来设计软件&a…

使用 GitHub Copilot 进行 Prompt Engineering 的初学者指南(译)

文章目录 什么是 GitHub Copilot ?GitHub Copilot 可以自己编码吗&#xff1f;GitHub Copilot 的底层是如何工作的&#xff1f;什么是 prompt engineering?这是 prompt engineering 的另一个例子 使用 GitHub Copilot 进行 prompt engineering 的最佳实践提供高级上下文&…

0139 数据链路层1

目录 3.数据链路层 3.1数据链路层的功能 3.2组帧 3.3差错控制 3.4流量控制与可靠传输机制 3.5介质访问控制 部分习题 3.数据链路层 3.1数据链路层的功能 3.2组帧 3.3差错控制 3.4流量控制与可靠传输机制 3.5介质访问控制 部分习题 1.数据链路层协议的功能不包括&…

【雕爷学编程】MicroPython动手做(30)——物联网之Blynk 2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

docker删除容器(步骤详解)

要在Docker中删除容器&#xff0c;需要使用命令docker rm。 下面是详细步骤&#xff1a; 1. 首先&#xff0c;使用docker ps命令查看当前正在运行的容器。这个命令会列出所有正在运行的容器的ID、名称、状态等信息。 如果没有正在运行的容器可以通过docker ps -a 查看当前所…

数据结构 | Radix Tree 树

什么是基数树&#xff1f; 基数树是一种多叉搜索树&#xff0c;数据位于叶子节点上&#xff0c;每一个节点有固定的2^n个子节点&#xff08;n为划分的基大小&#xff0c;当n为1时&#xff0c;为二叉树&#xff09;。 什么为划分的基&#xff1f; 以一个64位的长整型为例&#x…

Day08-作业(MySQLMybatis入门)

作业1&#xff1a;多表查询 数据准备&#xff1a; 重新创建一个数据库 db03_homework 执行如下脚本&#xff0c;创建表结构&#xff0c;导入测试数据 -- 部门管理 create table tb_dept(id int unsigned primary key auto_increment comment 主键ID,name varchar(10) not n…

ubuntu git操作记录设置ssh key

用到的命令&#xff1a; 安装git sudo apt-get install git配置git用户和邮箱 git config --global user.name “用户名” git config --global user.email “邮箱地址”安装ssh sudo apt-get install ssh然后查看安装状态&#xff1a; ps -e | grep sshd4. 查看有无ssh k…

通过案例实战详解elasticsearch自定义打分function_score的使用

前言 elasticsearch给我们提供了很强大的搜索功能&#xff0c;但是有时候仅仅只用相关度打分是不够的&#xff0c;所以elasticsearch给我们提供了自定义打分函数function_score&#xff0c;本文结合简单案例详解function_score的使用方法&#xff0c;关于function-score-query…

【Spring】深究SpringBoot自动装配原理

文章目录 前言1、main入口2、SpringBootApplication3、EnableAutoConfiguration4、AutoConfigurationImportSelector4.1、selectImports()4.2、getAutoConfigurationEntry()4.3、getCandidateConfigurations()4.4、loadFactoryNames() 5、META-INF/spring.factories6、总结 前言…

Nginx实现反向代理和负载均衡

Nginx安装 本文章主要介绍下&#xff0c;如何使用Nginx来实现反向代理和负载均衡&#xff0c;Nginx安装和基础知识&#xff0c;可参考我的这篇文章 Nginx安装。 Nginx实现反向代理 实现反向代理需要准备两台Nginx服务器。一台Nginx服务器A&#xff0c;ip为 192.168.206.140&…

浅谈机器视觉

目录 1.什么是机器视觉 2.学习机器视觉需要掌握的知识 3.机器视觉的由来 4.机器视觉带来的福利 1.什么是机器视觉 机器视觉&#xff08;Computer Vision&#xff09;是人工智能领域中的一个分支&#xff0c;旨在通过模仿人类的视觉系统&#xff0c;使计算机能够理解和解释图…

【Leetcode】(自食用)找到消失的数字

step by step. 题目&#xff1a; 给你一个含 n 个整数的数组 nums &#xff0c;其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字&#xff0c;并以数组的形式返回结果。 示例 1&#xff1a; 输入&#xff1a;nums [4,3,2,7,8,2,3,1] 输…

Stable Diffusion教程(6) - 扩展安装

打开stable diffusion webUI界面 加载插件列表 依次点击扩展->可用->加载自 搜索插件 首先在搜索框输入你要安装的插件&#xff0c;然后点击插件后面的安装按钮 如果你需要的插件这里面没有找到&#xff0c;可通过通网址安装的方式安装。 在git仓库网址输入框输入的你插件…

分享 一个类似 ps 辅助线功能

效果图片&#xff1a; 提示&#xff1a;这里的样式我做边做了修改&#xff0c;根据个人情况而定。 //你也可以npm下载 $ npm install --save vue-ruler-tool特点 没有依赖可拖动的辅助线快捷键支持 开始使用 1. even.js /*** description 绑定事件 on(element, event, han…

FPGA项目设计:数字时钟

项目要求&#xff1a; 设计一个数字时钟&#xff0c;数码管前两位显示小时&#xff0c;数码管中间两位显示分钟&#xff0c;数码管后面两位显示秒。 项目设计&#xff1a; 系统框架图&#xff1a; 计数模块时序图&#xff1a; 代码实现&#xff1a; 计数模块&#xff1a; /…