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

这篇具有很好参考价值的文章主要介绍了二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

算法模板

二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表

Dijkstra题目代码模板

朴素dijkstra算法

对应模板题:Dijkstra求最短路 I
时间复杂是 O(n^2+m):n 表示点数,m 表示边数
二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表
二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表
二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表

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 表示边数
二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表
二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表
二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表

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[]的理解

二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表
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.
二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表

关于堆的原理与操作

二、数据结构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

思路

二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表
二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表

题解

#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进行操作
二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency),算法与数据结构模板,图论,算法,数据结构,c++,链表
关于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算法)文章来源地址https://www.toymoban.com/news/detail-624430.html

到了这里,关于二、搜索与图论6:Dijkstra 模板题+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Dijkstra算法求最短路

    Dijkstra算法的流程如下: 1.初始化dist[1] = 0,其余节点的dist值为无穷大。 2.找出一个未被标记的、dist[x]最小的节点x,然后标记节点x。 3.扫描节点x的所有出边(x,y,z),若dist[y] dist[x] + z,则使用dist[x] + z更新dist[y]。 4.重复上述2~3两个步骤,直到所有的节点都被标记。 Dijk

    2024年02月06日
    浏览(44)
  • 图算法——求最短路径(Dijkstra算法)

            目录 一、什么是最短路径 二、迪杰斯特拉(Dijkstra)算法  三、应用Dijkstra算法 (1) Dijkstra算法函数分析         求图的最短路径在实际生活中有许多应用,比如说在你在一个景区的某个景点,参观完后,要怎么走最少的路程到你想参观的下个景点,这就利用到

    2023年04月15日
    浏览(40)
  • 第三章 搜索与图论(二)(最短路)

    1、对于稠密图,由于朴素版的dijkstra算法与边数无关使用这种算法的复杂度较低。稀疏图用堆优化版的算法;单源最短路中存在负权边用SPFA 算法通常较好;多源用floyd算法;  难点:如何建图,抽象为最短路问题。 由于稠密图用这种算法,邻接矩阵存图,注意把g初始化为

    2024年02月21日
    浏览(45)
  • 搜索与图论第六期 最短路问题

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

    2024年02月20日
    浏览(42)
  • 第三章 搜索与图论(二)——最短路问题

    源点表示起点,汇点表示终点 一些认识: m和 n 2 n^2 n 2 一个级别是稠密图,m和n一个级别是稀疏图 最短路问题不区分有向图与无向图,因为无向图是一种特殊的有向图,能解决有向图的最短路问题,就能解决无向图的最短路问题 起点确定,终点是除起点外的其他点 默认n表示

    2024年02月13日
    浏览(41)
  • 12.图论1 最短路之dijkstra算法

    二分图 判定:染色法。 性质: 可以二着色。 无奇圈。 树的直径模板 两遍dfs/bfs,证明时反证法的核心是用假设推出矛盾。 设1是一开始随机选的点,s是与其最远的点,证明s是直径的一端。 反证:假设s不是直径的一端,ss是直径的一端。 现在要做的就是证明ss是直径的一端

    2024年02月20日
    浏览(47)
  • 图论算法基础:单源最短路径Dijkstra算法分析

    在 有向带权图 中给定一个起始顶点(源点),Dijkstra算法可以求出 所有其他顶点 到源点的最短路径,Dijkstra算法 不能用于同时含有正负权值的边的图 Source 顶点集合:已经确定 到源点的最短路径 的顶点就会加入 Source 集合中, Source 集合初始时只有源点 dist 数组:用于记录每个顶点到

    2024年02月11日
    浏览(44)
  • 【图论算法】最短路径算法(无权最短路径、Dijkstra算法、带负边值的图、无圈图)

    本篇博客将考察各种最短路径问题。     无权最短路径     Dijkstra 算法     具有负边值的图     无圈图     所有顶点对间的最短路径     最短路径的例子–词梯游戏 输入是一个赋权图:与每条边 (v i , v j ) 相联系的是穿越该边的开销(或称为值

    2023年04月12日
    浏览(43)
  • 图论:最短路(dijkstra算法、bellman算法、spfa算法、floyd算法)详细版

    终于是学完了,这个最短路我学了好几天,当然也学了别的算法啦,也是非常的累啊。 话不多说下面看看最短路问题吧。 最短路问题是有向图,要求的是图中一个点到起点的距离,其中我们要输入点和点之间的距离,来求最短路。 下面分为几类题目: 单源汇最短路--一个起

    2024年01月21日
    浏览(44)
  • dijkstra模板及例题(最短路算法)

            大家好,我是永遇乐金枪鱼。图论和树论是算法中占比大且非常重要的内容,而且树论是特殊的图论,而图论中最经典的就是求解最短路,而最短路算法是比较广泛且冗杂的算法,与其相关的有较多的算法,下面我给大家讲讲常用算法之一——dijkstra算法。  📒博客

    2023年04月08日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包