图论复习(最短路、最小生成树)

图论复习

拓扑排序

原题链接:AcWing 848. 有向图的拓扑序列 - AcWing

在建图时,记录每个节点的入度,首先把入度为0的点都存到队列里。

然后在搜索时,每搜到一个点,就把这个点的入度 -1 ,当它的入度变为0时,就把它存到队列里。直到队列里全部的点都搜索完。

这时要判断一下是否所有的点的入度都为0了。如果是,那么就找到了一个拓扑序列;否则就没有找到。

#include<bits/stdc++.h>using namespace std;
const int N = 3e5;
int h[N], e[N], ne[N], w[N], idx;
int n, m;
int d[N];
int q[N];
int hh = 0, tt = -1;void add(int a, int b)
{e[idx] = b; ne[idx] = h[a]; h[a] = idx++;
}void bfs()
{while (hh <= tt){int t = q[hh++];for (int i = h[t]; i!=-1; i = ne[i]){int j = e[i];d[j]--;if (d[j] == 0){q[++tt] = j;}}}for (int i = 1; i <= n; i++){if(d[i]!=0){cout<<-1<<endl;return;}}for(int i = 0;i<n;i++)cout<<q[i]<<" ";}
int main()
{int a, b;cin >> n >> m;memset(h,-1,sizeof h);for (int i = 1; i <= m; i++){cin >> a >> b;add(a, b);d[b]++;	//入度+1}int k;for (int i = 1; i <= n; i++){if (d[i] == 0){q[++tt]=i;}}bfs();return 0;
}



dijkstra算法 堆优化

原题链接:850. Dijkstra求最短路 II - AcWing题库

利用优先队列优化dijkstra算法。注意优先队列的定义方式(默认为大根堆,而求最短路要使用小根堆)

priority_queue<int,vector<int>,less<int> > q;	//默认形式,大根堆
priority_queue<int,vector<int>,greater<int> > q;	//大根堆形式

下面展示dijkstra(用结构体定义的优先队列)

#include<bits/stdc++.h>using namespace std;
const int N = 2e5, M = 4e5;
int h[N], e[M], ne[M],w[M], idx;
int n, m;
int dist[N];struct node
{int dist;int id;bool operator < (const node& t)const	//默认大根堆,所以要用大于号重载小于号{if (dist == t.dist)return id > t.id;return dist > t.dist;}
};
node p[N];
priority_queue<node> q;
bool st[N];void add(int a, int b, int c)
{e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
}void dijkstra(int k)
{memset(dist, 0x3f, sizeof dist);dist[k] = 0;q.push({ 0,1 });while (!q.empty()){auto t = q.top();q.pop();if (st[t.id] == true)continue;st[t.id] = true;for (int i = h[t.id]; ~i; i = ne[i]){int j = e[i];if (dist[j] > dist[t.id] + w[i]){dist[j] = dist[t.id] + w[i];q.push({ dist[j],j });}}}if (dist[n] > 0x3f3f3f3f / 2)cout << -1 << endl;elsecout << dist[n] << endl;return;
}
int main()
{int a, b, c;cin >> n >> m;memset(h, -1, sizeof h);for (int i = 1; i <= m; i++){cin >> a >> b >> c;add(a, b, c);}dijkstra(1);return 0;
}



有边数限制的最短路问题——bellman-ford

原题链接:853. 有边数限制的最短路 - AcWing题库

#include<bits/stdc++.h>using namespace std;
const int M = 1e5;
int n, m, k;
struct node
{int a, b, c;
};
node p[M];
int dist[M], backup[M];void bellman()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;for (int i = 0; i < k; i++){memcpy(backup, dist, sizeof dist);for (int j = 0; j < m; j++){auto e=p[j];if (dist[e.b] > backup[e.a] + e.c){dist[e.b] = backup[e.a] + e.c;}// dist[e.b] = min(dist[e.b] ,backup[e.a]+e.c);}}if (dist[n] > 0x3f3f3f3f / 2)cout << "impossible";elsecout << dist[n];
}
int main()
{cin >> n >> m >> k;for (int i = 0; i < m; i++){int a,b,c;cin>>a>>b>>c;p[i]={a,b,c};
// 		cin >> p[i].a >> p[i].b >> p[i].c;}bellman();return 0;
}



SPFA算法(最短路、求负环)

原题链接:851. spfa求最短路 - AcWing题库

思路分析

spfa算法适用于在有负权的图中求最短路的问题。

spfa 于 dijkstra的区别主要有两点

  • 数据结构的使用:dijkstra使用优先队列,而spfa使用普通的队列即可
  • st[]数组的目的不同:dijkstra的st[]是记录每个点是否已经搜过了。而spfa的st[]则记录的是该点是否在队列中。
#include<bits/stdc++.h>using namespace std;
const int N = 3e5;
int h[N], ne[N], e[N], w[N], idx;
int n, m;
queue<int> q;
int dist[N];
bool st[N];void add(int a, int b, int c)
{e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
}void spfa()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;q.push(1);st[1] = true;while (!q.empty()){int t = q.front();q.pop();st[t] = false;for (int i = h[t]; ~i; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];if (!st[j]){q.push(j);st[j]=true;}}}}if (dist[n] > 0x3f3f3f3f / 2)cout << "impossible";elsecout << dist[n];
}int main()
{int a, b, c;memset(h,-1,sizeof h);cin >> n >> m;for (int i = 1; i <= m; i++){cin >> a >> b >> c;add(a, b, c);}spfa();return 0;
}

原题链接:852. spfa判断负环 - AcWing题库

思路分析

怎么判断是否存在负环?

需要设置一个新的数组cnt[],用来记录在最短路中所经过的边的数量。

如果存在一个cnt[j],使得它大于 n ,也就是说,此时肯定存在一个多余的边——也就是形成了环。又因为在求最短路的过程中,满足条件的dist[]是不断更新变小的,所以存在一个可以使最短路不断变小的环——也就是 负环!

#include<bits/stdc++.h>using namespace std;
const int N = 3e5;
int h[N], ne[N], e[N], w[N], idx;
int n, m;
queue<int> q;
int dist[N],cnt[N];
bool st[N];void add(int a, int b, int c)
{e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
}bool spfa()
{memset(dist, 0x3f, sizeof dist);	//因为我们并不关心最短路的大小,所以这里初始化可以随意设置for (int i = 1; i <= n; i++)	//这里是把所有的节点都先放到队列里。因为如果只放q.push(1),意思就是寻找 节点1到其余所有节点的最短路中是否存在负环。但是题目是有向边,所以要考虑所有节点到其他所有节点的最短路中是否存在有向边。{st[i] = true;q.push(i);}while (!q.empty()){int t = q.front();q.pop();st[t] = false;for (int i = h[t]; ~i; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];cnt[j] = cnt[t] + 1;	//边数+1,判断是否存在负环。if (cnt[j] >= n)	return true;if (!st[j])	//如果不在队列里面,就把它放到队列里去。{st[j] = true;q.push(j);}}}}return false;
}int main()
{int a, b, c;cin >> n >> m;memset(h,-1,sizeof h);for (int i = 1; i <= m; i++){cin >> a >> b >> c;add(a, b, c);}if (spfa())cout << "Yes\n";elsecout << "No\n";return 0;
}



Floyd算法——多源最短路

原题链接:854. Floyd求最短路 - AcWing题库

思路分析

利用了dp的思想。

如果要求点i到点j的最短距离dist[i][j],如果要更新dist[i][j] 那么就要用到另一个中间点k,即:dist[i][j] = min(dist[i][j],dist[i][k] + dist[k][j])

而对于任意两点i , j以及这个中间节点 k 。它们的取值范围都是1–n的。

那么可以用如下for循环表示:

for (int k = 1; k <= n; k++)	//中间节点k放在for循环的最外面,表示首先考虑节点1作为中间节点时,所有节点的最短路径。然后再通过节点2 3 4 ... 作为中间节点。
{for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);}}
}

整体代码:

#include<bits/stdc++.h>using namespace std;
const int N = 1010;
int dist[N][N];
int n, m, l;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] = min(dist[i][j], dist[i][k] + dist[k][j]);}}}
}
int main()
{cin >> n >> m >> l;memset(dist, 0x3f, sizeof dist);for(int i = 1;i<=n;i++)		//注意节点到自身的距离初始化为0dist[i][i]=0;for (int i = 1; i <= m; i++){int a, b, c;cin >> a >> b >> c;dist[a][b] = min(dist[a][b],c);	//因为要求最小值,所以要记录最小值(处理重边)}floyd();for (int i = 1; i <= l; i++){int a, b;cin >> a >> b;if (dist[a][b] > 0x3f3f3f3f / 2)cout << "impossible\n";elsecout << dist[a][b] << "\n";}return 0;
}



Prim算法求最小生成树

原题链接:858. Prim算法求最小生成树 - AcWing题库

思路分析

首先应该知道,Prim算法求最小生成树,适用于稠密图,故直接用邻接矩阵来存储。

Prim的算法思想和dijkstra很像。

dijkstra的思想是:

  • 建立一个dist[]表示每个点距离起点的最短路径,并将其初始化为0x3f(起点初始化为0)

  • 利用bool数组st[]记录点是否在集合里(最短路里面)

  • 找到集合外的 距离起点最近的点,并用它更新其他点到起点的距离

而prim的思想是:

  • 找到集合外的 距离集合最近的点并用它更新其他点到该集合的距离 (这里的集合是指生成树)
#include<bits/stdc++.h>using namespace std;
const int N = 1010;int g[N][N];
int n, m;
int dist[N];
int pre[N];	//用于记录前置节点,可以打印输出路径
bool st[N];
int res;void prim()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;	//假如从第一个节点开始,来生成最小生成树(注意这里从哪个节点开始并不影响)for (int i = 1; i <= n; i++)	//寻找每个节点{int t = -1;for (int j = 1; j <= n; j++)	//找到一个在集合外,并且距离集合最近的节点{if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;}	cout<<t<<endl;//如果找不到这个点,就输出不可能if (dist[t] == 0x3f3f3f3f){cout << "impossible";return;}st[t] = true;	//找到点就把它加入到集合里面去res += dist[t];	//更新最短路的距离,注意这里的距离要放在dist[t]更新之前,因为有可能会有自环的情况,导致dist变小,但是自环并不能生成树//用该节点更新其他节点到集合的距离for (int j = 1; j <= n; j++){if (dist[j] > g[t][j] && !st[j]){dist[j] = g[t][j];pre[j] = t;	//更新前置节点}}}cout << res;
}int main()
{cin >> n >> m;memset(g, 0x3f, sizeof g);for (int i = 1; i <= n; i++)g[i][i] = 0;for (int i = 1; i <= m; i++){int a, b, c;cin >> a >> b >> c;g[a][b] = g[b][a] = min(g[a][b], c);}prim();// 	for(int i = n;i>=1;i--)
// 	{
// 	    cout<<endl<<i<< ' '<<pre[i];
// 	}return 0;
}



Kruskal算法求最小生成树

原题链接:859. Kruskal算法求最小生成树 - AcWing题库

思路分析

kruskal算法是按照边的大小来构建生成树的,具体思路如下:

  • 首先把所有的边按照权重从小到大的顺序排序

  • 接着把在集合(生成树)之外的边,按照顺序依次添加进去 (利用并查集,快速的判断是否在集合内)

  • 如果最终集合里边的数量,恰好为点n的数量减一,那么就生成成功了。

代码如下

#include<bits/stdc++.h>using namespace std;
const int N = 2e5 + 5;
struct node
{int a, b, c;bool operator< (const node& t)const	//重载小于号,按照权重从小到大的顺序排序{return c < t.c;}
};node p[N];
int n, m;
int fa[N];	//记录父节点
int res;	//是最小生成树的权重之和
int cnt;	//记录进入生成树的边的数量,用与判断是否生成成功int find(int x)	//并查集
{if (fa[x] != x)	//如果该节点的父节点不是他自己(也就是说它不是祖先节点),fa[x] = find(fa[x]);	//那么就递归查询它的父节点return fa[x];	//最终返回它的父节点
}
int main()
{cin >> n >> m;for (int i = 1; i <= m; i++){int a, b, c;cin >> a >> b >> c;p[i] = { a,b,c };}sort(p + 1, p + 1 + m);for (int i = 1; i <= n; i++)	//并查集要初始化!每个节点的最初的父节点都是自己fa[i] = i;for (int i = 1; i <= m; i++){int a = p[i].a, b = p[i].b, c = p[i].c;a = find(a), b = find(b);	//分别找到这条边的两个端点的父节点if (a != b)	//如果这两个点不属于同一个父节点,也就是说这条边不在集合里{fa[a] = b;	//把集合a并入到b里去res += c;	//更新权重cnt++;		//更新边数}}if (cnt == n - 1){cout << res;}elsecout << "impossible\n";return 0;
}

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

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

相关文章

Flutter开发进阶之瞧瞧BuildOwner

Flutter开发进阶之瞧瞧BuildOwner 上回说到关于Element Tree的构建还缺最后一块拼图&#xff0c;build的重要过程中会调用_element!.markNeedsBuild();&#xff0c;而markNeedsBuild会调用owner!.scheduleBuildFor(this);。 在Flutter框架中&#xff0c;BuildOwner负责管理构建…

计算机视觉之三维重建(2)---摄像机标定

文章目录 一、回顾线代1.1 线性方程组的解1.2 齐次线性方程组的解 二、透镜摄像机的标定2.1 标定过程2.2 提取摄像机参数2.3 参数总结 三、径向畸变的摄像机标定3.1 建模3.2 求解 四、变换4.1 2D平面上的欧式变换4.2 2D平面上的相似变换和仿射变换4.3 2D平面上的透射变换4.4 3D…

使用 VMWare 安装 Android-x86 系统(小白版)

文章目录 VMWare 介绍Android 系统介绍概述最终效果前置步骤开始安装 VMWare 介绍 VMware Workstation是VMware公司开发的一款桌面虚拟化软件。它允许用户在一台物理计算机上同时运行多个操作系统&#xff0c;每个操作系统都在自己的虚拟机中运行。这使得用户可以在同一台计算…

实例:NX二次开发使用链表进行拉伸功能(链表相关功能练习)

一、概述 在进行批量操作时经常会利用链表进行存放相应特征的TAG值&#xff0c;以便后续操作&#xff0c;最常见的就是拉伸功能。这里我们以拉伸功能为例子进行说明。 二、常用链表相关函数 UF_MODL_create_list 创建一个链表&#xff0c;并返回链表的头指针。…

认识String类

认识String类 前面我们学习了类和对象&#xff0c;这一小节咱们来谈String类 目录 认识String类前言一、String类的创建方式二、String引用类型的特点及方法1.存储内容2.String对象的比较3.字符串查找在这里插入图片描述4.转换&#xff08;一&#xff09;数字转为为字符串&…

阿里云原生:如何熟悉一个系统

原文地址:https://mp.weixin.qq.com/s/J8eK-qRMkmHEQZ_dVts9aQ?poc_tokenHMA-_mWjfcDmGVW6hXX1xEDDvuJPE3pL9-8uSlyY 导读&#xff1a;本文总结了熟悉系统主要分三部分&#xff1a;业务学习、技术学习、实战。每部分会梳理一些在学习过程中需要解答的问题&#xff0c;这些问题…

单片机MCU,MPU,SOC的工艺结构原理及选型参数总结

🏡《总目录》 目录 1,概述2,工作原理2.1,时钟系统2.2,存储器系统2.3,处理器2.4,输入输出系统3,结构特点3.1,中央处理器(CPU)3.2,存储器3.3,I/O端口3.4,定时器/计数器3.5,中断系统3.6,

集成学习 | 集成学习思想:Stacking思想

目录 一. Stacking 思想 一. Stacking 思想 Stacking(或stacked generalization)&#xff0c;是指训练一个模型用于组合(combine)其他各个模型 Stacking有两层第一层是不同的基学习器&#xff08;classifiers/regressors&#xff09;第二层是用于组合基学习器的元学习&#xf…

怎么实现redis的高可用

要实现 Redis 的高可用性&#xff0c;可以考虑以下几种方法&#xff1a; 主从复制&#xff08;Master-Slave Replication&#xff09;&#xff1a; 在 Redis 中&#xff0c;可以配置主从复制&#xff0c;将主节点的数据同步到从节点&#xff0c;当主节点宕机时&#xff0c;可以…

Reactor Netty

在springframework 里面&#xff0c;我们只有connection id。但是在底层的reactor netty,我们除了connection id还有local address and remote address HTTP/1 HTTP/2

Qt creator构建DLL库

文章目录 一、构建DLL库二、隐式调用DLL库 一、构建DLL库 Qt creator创建DLL项目。 实现功能函数。 运行代码&#xff0c;debug目录下会有.dll和.lib文件。 二、隐式调用DLL库 QT新建控制台项目。将.lib文件和与之关联的头文件赋值到项目文件夹。 3. 添加头文件和外部依赖库…

GuLi商城-商品服务-API-三级分类-网关统一配置跨域

参考文档&#xff1a; https://tangzhi.blog.csdn.net/article/details/126754515 https://github.com/OYCodeSite/gulimall-learning/blob/master/docs/%E8%B0%B7%E7%B2%92%E5%95%86%E5%9F%8E%E2%80%94%E5%88%86%E5%B8%83%E5%BC%8F%E5%9F%BA%E7%A1%80.md 谷粒商城-day04-完…

[数据结构初阶]二叉树

各位读者老爷好&#xff0c;鼠鼠我现在浅浅介绍一些关于二叉树的知识点&#xff0c;在各位老爷茶余饭后的闲暇时光不妨看看&#xff0c;鼠鼠很希望得到各位老爷的指正捏&#xff01; 开始介绍之前&#xff0c;给各位老爷看一张风景照&#xff0c;有读者老爷知道在哪里吗&#x…

003- AutoCoder 使用Web版大模型,性感的Human As Model 模式

这是下面这篇文章的继续。 002- 用 AutoCoder 添加和修改代码 前面我们提到&#xff0c;如何解决你没有API版大模型&#xff0c;或者你的API版大模型太弱&#xff0c;而你只有Web版本的诸如 Kimi/GPT4 的情况下&#xff0c;改如何让AutoCoder帮助你完成编程&#xff1f; 我们有…

Excel数字乱码怎么回事 Excel数字乱码怎么调回来

在日常工作中&#xff0c;Excel是我们最常使用的数据处理软件之一&#xff0c;它强大的功能使得数据处理变得既简单又高效。然而&#xff0c;用户在使用Excel时偶尔会遇到数字显示为乱码的问题&#xff0c;这不仅影响了数据的阅读&#xff0c;也大大降低了工作效率。那么&#…

StringRedisTemplate Autowired注入为空解决

如下注入方式报空指针异常&#xff1a; java.lang.NullPointerException: null Autowiredprivate StringRedisTemplate redisTemplate; 解决办法&#xff1a;查看该类上有没有加注解&#xff0c;如Component等&#xff0c;没加的话加上。 还有一种是在工具类中使用&#xff0c;…

会员中心微服务

文章目录 1.环境配置1.创建会员中心模块2.检查父子模块的pom.xml1.父模块注意&#xff1a;如果父模块中的依赖显示not found&#xff0c;原因是子模块并没有引用&#xff0c;不用在意 2.子模块 3.pom.xml 引入相关依赖&#xff08;别忘记刷新maven&#xff09;4.application.ym…

【Node.js】全局变量和全局 API

node 环境中没有 dom 和 bom &#xff0c;此外 es 基本上都是可以正常使用的。 如果一定要使用 dom 和bom&#xff0c;可以借助第三方库 jsdom 帮助我们实现操作。npm i jsdom 实例&#xff1a; const fs require(node:fs) const {JSDOM} require(jsdom)const dom new JS…

scrapy爬虫框架

scrapy爬虫框架 一、scrapy的概念作用和工作流程1、scrapy的概念2、scrapy框架的作用3、scrapy的工作流程&#xff08;重点&#xff09;3.1 回顾之前的爬虫流程3.2 改写上述流程3.3 scrapy的流程3.4 scrapy的三个内置对象3.5 scrapy中每个模块的具体作用 二、scrapy的入门使用1…

第十节:Vben Admin实战-系统管理之角色管理实现(分页查询,修改)-中

系列文章目录 第一节:Vben Admin介绍和初次运行 第二节:Vben Admin 登录逻辑梳理和对接后端准备 第三节:Vben Admin登录对接后端login接口 第四节:Vben Admin登录对接后端getUserInfo接口 第五节:Vben Admin权限-前端控制方式 第六节:Vben Admin权限-后端控制方式 第七节…