数据结构-并查集专题(2)

一、前言

接(1)完成剩余题目和了解并查集运用求解最小生成树的Kruskal算法

二、专题训练

2.1 题目总览

前四题见(1)

2.2 1568: 并查集-家谱

思路

首先这个题目的描述就有问题,它说每一组的父子关系由两行组成,那样例的第3到第5行你要怎么解释,麻了。这里应该是#开头的是父亲,下面紧跟着的若干行+开头的都是他的儿子。而且这个题也是不适合用我们的模板去解的,因为它需要从字符串映射到字符串,当然你也可以给字符串编个序号这样也可以实现,我这里给出另一种解法,我们用哈希表来实现字符串到字符串的映射。其余的就是并查集的基本操作了

参考代码

#include <bits/stdc++.h>
#include <functional>
using i64 = long long;using pss = std::pair<std::string,std::string>;int main() {std::cin.tie(nullptr)->sync_with_stdio(false);std::vector<pss> v;pss pair = {"",""};std::vector<std::string> query;std::string line;std::unordered_map<std::string,std::string> fa;std::string father,son;using Find = std::function<std::string(std::string)>;Find find = [&](std::string x)  {if(x!=fa[x]) fa[x] = find(fa[x]);return fa[x];};while(std::getline(std::cin,line)) {if(line[0]=='#') {father = line.substr(1);if(fa[father]=="") fa[father] = father;}else if(line[0]=='+') {son = line.substr(1);if(fa[son]=="") {fa[son] = find(father);}}else if(line[0]=='?') {query.emplace_back(line.substr(1));}else {//line[0]=='$'break;}}for(auto &str:query) {std::cout << str << ' ' << find(str) << '\n';}return 0;
}

2.3 1836: 并查集-格子游戏

思路

对于并查集来说,一个节点的值最常见的是一个int,上一题节点的值是一个字符串,这道题节点的值是一个坐标点,当然你可以像上一题一样,写一个坐标的结构体,然后用哈希表将坐标映射到坐标,我这里采用将坐标变换成一个int,然后每次操作时判断,要连接的两个点是否已经在同一个并查集中了,如果是则输出当前的步数,如果不是则将两个节点进行合并,执行到结束,如果游戏仍然没有结束则输出"draw"

参考代码

注意并查集初始化的时候,空间要开大一些

#include <bits/stdc++.h>
using i64 = long long;struct DisjointSet {int _n;std::vector<int> _fa,_size;DisjointSet(){}DisjointSet(int n){init(n);}void init(int n) {_fa.resize(n);std::iota(_fa.begin(),_fa.end(),0);_size.assign(n,1);}int find(int x) {if(x!=_fa[x]) {_fa[x] = find(_fa[x]);}return _fa[x];}bool same(int x,int y) {return find(x)==find(y);}bool merge(int x,int y) {int fx = find(x);int fy = find(y);if(fx!=fy) {_size[fx]+=_size[fy];_fa[fy] = fx;return true;}return false;}
};int main() {std::cin.tie(nullptr)->sync_with_stdio(false);int n,m;std::cin >> n >> m;DisjointSet disjointSet = DisjointSet((n+5)*(n+2));for(int i = 0;i<m;i++) {int x1,y1,x2,y2;std::cin >> x1 >> y1;std::string op;std::cin >> op;if(op=="D") {x2 = x1+1,y2 = y1;}else {x2 = x1,y2 = y1+1;}int t1 = n*(x1-1)+y1-1,t2 = n*(x2-1)+y2-1;if(!disjointSet.merge(t1,t2)) {std::cout << i+1 << '\n';return 0;}}std::cout << "draw" << '\n';return 0;
}

2.4 1837: 并查集-亲戚

思路

此题思路很一般,正常做就行,但是因为数据量的限制,我们写并查集的时候一定要做路径压缩,不然会TLE,直接用我们的模板就行

参考代码

#include <bits/stdc++.h>
using i64 = long long;struct DisjointSet {int _n;std::vector<int> _fa,_size;DisjointSet(){}DisjointSet(int n){init(n);}void init(int n) {_fa.resize(n);std::iota(_fa.begin(),_fa.end(),0);_size.assign(n,1);}int find(int x) {if(x!=_fa[x]) {_fa[x] = find(_fa[x]);}return _fa[x];}bool same(int x,int y) {return find(x)==find(y);}bool merge(int x,int y) {int fx = find(x);int fy = find(y);if(fx!=fy) {_size[fx]+=_size[fy];_fa[fy] = fx;return true;}return false;}
};int main() {std::cin.tie(nullptr)->sync_with_stdio(false);int n,m;std::cin >> n >> m;DisjointSet disjointSet = DisjointSet(n+1);for(int i = 0;i<m;i++) {int x,y;std::cin >> x >> y;disjointSet.merge(x,y);}int q;std::cin >> q;while(q--) {int x,y;std::cin >> x >> y;std::cout << (disjointSet.same(x,y)?"Yes\n":"No\n");}return 0;
}

三、并查集的运用

3.1 最小生成树

最小生成树是一个现实中经常遇到的问题,各个城镇直接修路、修桥,我们力争使用的材料或者经费最少,就需要求出最小生成树

3.2 Prim算法(基于贪心算法,与求最短路的Dijkstra算法类似)

3.3 Kruskal算法(也是基于贪心算法,需要用到并查集)

把带权边按照权值升序排序,开始循环找当前权值最小的边,如果两个节点不在同一个并查集中,则将它们合并,如果在同一个并查集中,则继续找下一条边。循环结束,如果有n-1条边,则成功找到最小生成树(最小生成树不唯一,但最后的权值和最小是唯一的),如果循环结束,找不到n-1条边,则不存在最小生成树

3.3.1 例题1 AcWing 859. Kruskal算法求最小生成树

思路

没啥好说的,是一个模板题

参考代码
#include <bits/stdc++.h>
using i64 = long long;struct Edge {int _x, _y, _w;Edge(int x, int y, int w) : _x(x), _y(y), _w(w) {}bool operator<(const Edge& edge2) const {return _w < edge2._w;}
};struct DisjointSet {int _n;std::vector<int> _fa,_size;DisjointSet(){}DisjointSet(int n){init(n);}void init(int n) {_fa.resize(n);std::iota(_fa.begin(),_fa.end(),0);_size.assign(n,1);}int find(int x) {if(x!=_fa[x]) {_fa[x] = find(_fa[x]);}return _fa[x];}bool same(int x,int y) {return find(x)==find(y);}bool merge(int x,int y) {int fx = find(x);int fy = find(y);if(fx!=fy) {_size[fx]+=_size[fy];_fa[fy] = fx;return true;}return false;}
};int main() {std::cin.tie(nullptr)->sync_with_stdio(false);int n, m;std::cin >> n >> m;std::vector<Edge> edges;DisjointSet disjointSet(n);for (int i = 0; i < m; ++i) {int x, y, w;std::cin >> x >> y >> w;edges.emplace_back(x, y, w);}std::sort(edges.begin(), edges.end());int ans = 0, cnt = 0;for (const auto& edge : edges) {if (disjointSet.merge(edge._x, edge._y)) {ans += edge._w;++cnt;if (cnt == n - 1) break;}}std::cout << (cnt < n - 1 ? "impossible" : std::to_string(ans)) << '\n';return 0;
}

3.3.2 例题2 最小生成树-最优布线问题

 思路

题目的输入是邻接矩阵的形式,我们把它转换成边存储,然后再用Kruskal算法即可,当然这个题用Prim算法更合适

参考代码1(Kruskal算法)
#include <bits/stdc++.h>
using i64 = long long;struct Edge {int _x,_y,_w;Edge(int x,int y,int w):_x(x),_y(y),_w(w){}bool operator < (const Edge& edge2) const {return _w<edge2._w;}
};struct DisjointSet {int _n;std::vector<int> _fa,_size;DisjointSet(){}DisjointSet(int n){init(n);}void init(int n) {_fa.resize(n);std::iota(_fa.begin(),_fa.end(),0);_size.assign(n,1);}int find(int x) {if(x!=_fa[x]) {_fa[x] = find(_fa[x]);}return _fa[x];}bool same(int x,int y) {return find(x)==find(y);}bool merge(int x,int y) {int fx = find(x);int fy = find(y);if(fx!=fy) {_size[fx]+=_size[fy];_fa[fy] = fx;return true;}return false;}
};int main() {std::cin.tie(nullptr)->sync_with_stdio(false);int n;std::cin >> n;std::vector<Edge> edges;DisjointSet disjointSet = DisjointSet(n+1);for(int i = 1;i<=n;i++) {for(int j = 1;j<=n;j++) {int w;std::cin >> w;if(j>=i) {edges.emplace_back(i,j,w);}}}std::sort(edges.begin(),edges.end());int ans = 0;for(int i = 0;i<edges.size();i++) {int x = edges[i]._x,y = edges[i]._y,w = edges[i]._w;int fx = disjointSet.find(x),fy = disjointSet.find(y);if(disjointSet.merge(fx,fy)) {ans+=w;}}std::cout << ans << '\n';return 0;
}
参考代码2(Prim算法)
#include <iostream>
#include <cstring>
#include <type_traits>template<typename T1,typename T2>
typename std::common_type<T1,T2>::type min(T1 num1,T2 num2){return num1>num2?num2:num1;
}
int main(){std::cin.tie(nullptr)->sync_with_stdio(false);constexpr int MAX_N = 1e2+5,INF = 0x3f3f3f3f;int g[MAX_N][MAX_N];int dist[MAX_N];bool vis[MAX_N] {};int n;std::cin >> n;for(int i = 1;i<=n;++i){for(int j = 1;j<=n;++j){std::cin >> g[i][j];}}auto prim = [&]()->int{memset(dist,0x3f,sizeof dist);int res = 0;dist[1] = 0;for(int i = 0;i<n;++i){int t = -1;for(int j = 1;j<=n;++j){if(!vis[j]&&(t==-1||dist[j]<dist[t])) t = j;}if(dist[t]==INF) return INF;vis[t] = true;res+=dist[t];for(int j = 1;j<=n;++j) dist[j]=min(dist[j],g[t][j]);}return res;};std::cout << prim() << '\n';return 0;
}

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

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

相关文章

吾店云介绍 – 中国人的WordPress独立站和商城系统平台

经过多年在WordPress建站领域的摸索和探索&#xff0c;能轻松创建和管理各种类型网站的平台 – 吾店云建站平台诞生了。 应该说这是一个艰苦卓绝的过程&#xff0c;在中国创建一个能轻松创建和使用WordPress网站的平台并不容易&#xff0c;最主要是网络环境和托管软件的限制。…

测试实项中的偶必现难测bug--<pre>标签问题

问题描述: 用户从网上copy的简介信息可能带有<pre>标签,导致安卓上的内容只能一行滑动展示,但是ios有对这个标签做特殊处理: 分析: <pre> 标签是 HTML 中用于表示预格式化文本的标签,它的作用是保留文本中的空格、换行和缩进。它的全称是 preformatted text…

管理 Elasticsearch 变得更容易了,非常容易!

作者&#xff1a;来自 Elastic Ken Exner Elasticsearch 用户&#xff0c;我们听到了你的心声。管理 Elasticsearch 有时会变得很复杂&#xff0c;面临的挑战包括性能调整、问题检测和资源优化。我们一直致力于简化你的体验。今天&#xff0c;我们宣布了自收购 Opster 以来的一…

微波无源器件 OMT1 一种用于倍频程接收机前端的十字转门四脊正交模耦合器(24-51GHz)

摘要&#xff1a; 我们报道了一种用于天文学射电望远镜的毫米波波长接收机的一种十字转门四脊OMT的设计&#xff0c;制造和实测结果。此四脊OMT被直接兼容到一个四脊馈电喇叭来实现可以拓展矩形波导单模带宽的双极化低噪声接收机。使用了24-51GHz的带宽&#xff0c;OMT证实了0.…

CCS 学习记录

1.导入项目 在CCS菜单中选择Project->Import Existing CCS Eclipse Project&#xff0c;点击Browse找到CCS workspace所在文件夹&#xff0c;点击OK&#xff0c;CCS会自动将所选文件夹及其子文件夹下所有的CCS Projects列出。从列表中找到所要导入的项目文件夹&#xff0c;…

【在Typora中绘制用户旅程图和甘特图】

在 Typora 中可以使用 Mermaid 绘制用户旅程图&#xff08;User Journey Map&#xff09;&#xff0c;但由于 Mermaid 并不直接支持用户旅程图&#xff0c;我们可以通过一些图表的变通方式&#xff08;比如流程图或甘特图&#xff09;来表示用户旅程图的结构。用户旅程图通常展…

如何使用IDEA创建Maven/SSM工程?

鉴于很多学校还在教授SSMJSP&#xff0c;很多同学不会使用IDEA创建Maven工程&#xff0c;这里进行说明 windows下安装jdk并配置环境 添加链接描述Windows下安装Maven并配置环境 首先你要本地安装jdk&#xff0c;Maven并配置基础环境变量&#xff0c;然后对IDEA进行jdk、Mave…

网络安全常见面试题--含答案

本文面试题汇总&#xff1a; 防范常见的 Web 攻击 重要协议分布层 arp协议的工作原理rip协议是什么&#xff1f;rip的工作原理 什么是RARP&#xff1f;工作原理OSPF协议&#xff1f;OSPF的工作原理 TCP与UDP区别总结 什么是三次握手四次挥手&#xff1f; tcp为什么要三次握手&…

C++内存泄漏检查工具——Valgrind(--tool = memcheck)

在写c程序中通常遇到程序崩溃&#xff0c;我们首先想到的是内存问题 如果代码量少看几遍就能看得出来&#xff0c;如果代码量多起来我们就得借助一些工具了比如gdb调试和valgrind中得memcheck来解决内存问题 我用的ubuntu&#xff0c;先安装valgrind sudo apt update sudo a…

原生 JavaScript基本内容和常用特性详解

原生 JavaScript&#xff08;也称为 Vanilla JS&#xff09;指的是不依赖于任何框架或库的纯 JavaScript。以下是原生 JavaScript 的一些基本内容和常用特性详解。 目录 1. 数据类型 2. 变量声明 3. 控制结构 4. 函数 5. 对象和数组 6. 事件处理 7. DOM 操作 8. Promi…

库打包工具 rollup

库打包工具 rollup 摘要 **概念&#xff1a;**rollup是一个模块化的打包工具 注&#xff1a;实际应用中&#xff0c;rollup更多是一个库打包工具 与Webpack的区别&#xff1a; 文件处理&#xff1a; rollup 更多专注于 JS 代码&#xff0c;并针对 ES Module 进行打包webpa…

基于promtail+loki+grafana搭建日志系统

文章目录 Promtail安装promtail创建配置文件创建systemd 服务文件启动promtail服务 loki下载loki服务创建config.yml文件创建systemd服务文件启动loki grafana下载grafana 本文基于promtaillokigrafanaprometheus&#xff08;可选&#xff09; 搭建一个轻量快速的日志系统&…

微服务容器化部署实践(FontConfiguration.getVersion)

文章目录 前言一、整体步骤简介二、开始实战1.准备好微服务2.将各个微服务打包为镜像第一种第二种3. 将各个打包好的镜像,通过docker-compose容器编排,运行即可总结前言 docker容器化部署微服务: 将微服务容器化部署到 Docker 容器中是一个常见的做法,可以提高应用的可移…

人工智能(AI)和机器学习(ML)技术学习流程

目录 人工智能(AI)和机器学习(ML)技术 自然语言处理(NLP): Word2Vec: Seq2Seq(Sequence-to-Sequence): Transformer: 范式、架构和自注意力: 多头注意力: 预训练、微调、提示工程和模型压缩: 上下文学习、思维链、全量微调、量化、剪枝: 思维树、思维…

Python 操作数据库:读取 Clickhouse 数据存入csv文件

import pandas as pd from clickhouse_driver import Client import timeit import logging import threading from threading import Lock from queue import Queue from typing import List, Dict, Set from contextlib import contextmanager import os import time# 配置参…

SCP收容物211~215

注 &#xff1a;此文接SCP收容物201~210,本文只供开玩笑 ,与steve_gqq_MC合作 --------------------------------------------------------------------------------------------------------------------------------- 目录 scp-211 scp-212 scp-213 scp-214 scp-215 s…

带你读懂什么是AI Agent智能体

一、智能体的定义与特性 定义&#xff1a;智能体是一个使用大语言模型&#xff08;LLM&#xff09;来决定应用程序控制流的系统。然而&#xff0c;智能体的定义并不唯一&#xff0c;不同人有不同的看法。Langchain的创始人Harrison Chase从技术角度给出了定义&#xff0c;但更…

docker-compose在阿里云服务器上部署https所踩的各种坑(已成功部署)

前言 购买服务器&#xff0c;申请域名&#xff0c;申请证书&#xff0c;下载nginx证书&#xff0c;这些操作我就不说了&#xff0c;百度一大把&#xff0c;我只说一下部署中碰到的问题 问题 我们是docker-compose上部署的后台前台环境&#xff0c;配置https证书&#xff0c;…

Qt_day3_信号槽

目录 信号槽 1. 概念 2. 函数原型 3. 连接方式 3.1 自带信号 → 自带槽 3.2 自带信号 → 自定义槽 3.3 自定义信号 4. 信号槽传参 5. 对应关系 5.1 一对多 5.2 多对一 信号槽 1. 概念 之前的程序界面只能看&#xff0c;不能交互&#xff0c;信号槽可以让界面进行人机…

lua入门教程:math

在Lua中&#xff0c;math库是一个非常重要的内置库&#xff0c;它提供了许多用于数学计算的函数。这些函数可以处理各种数学运算&#xff0c;包括基本的算术运算、三角函数、对数函数、随机数生成等。结合你之前提到的Lua中的数字遵循IEEE 754双精度浮点标准&#xff0c;我们可…