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

news2024/11/25 20:30:53

一、前言

接(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.coloradmin.cn/o/2236523.html

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

相关文章

【销帮帮-注册_登录安全分析报告-试用页面存在安全隐患】

联通支付注册/登录安全分析报告 前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨…

中安OCR电子行驶证、驾驶证识别,助力便捷出行与智慧交通

随着数字化技术在各行各业的深入应用&#xff0c;交通管理领域也迈入了新的时代。OCR电子行驶证和电子驾驶证的推出&#xff0c;不仅提升了车辆及驾驶证件管理的效率&#xff0c;更大大方便了车主出行。电子证件的普及&#xff0c;使得交通管理从“实体化”逐渐走向“数字化”&…

《深度学习神经网络:颠覆生活的魔法科技与未来发展新航向》

深度学习神经网络对我们生活的影响 一、医疗领域 深度学习神经网络在医疗领域的应用可谓意义重大。在疾病诊断方面&#xff0c;它能够精准分析医疗影像&#xff0c;如通过对大量的 CT、MRI 图像进行深度学习&#xff0c;快速准确地识别出微小的肿瘤病变&#xff0c;为医生提供…

基于 SSM(Spring + Spring MVC + MyBatis)框架构建电器网上订购系统

基于 SSM&#xff08;Spring Spring MVC MyBatis&#xff09;框架构建电器网上订购系统可以为用户提供一个方便快捷的购物平台。以下将详细介绍该系统的开发流程&#xff0c;包括需求分析、技术选型、数据库设计、项目结构搭建、主要功能实现以及前端页面设计。 需求分析 …

C++入门基础知识142—【关于C++ 友元函数】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C 友元函数的相关内容&#xff01; 关于…

密码学是如何保护数据传输的安全性?

密码学通过一系列算法和协议来保护数据传输的安全性。 一、加密技术 对称加密算法 原理&#xff1a;使用相同的密钥进行加密和解密。应用&#xff1a;在数据传输过程中&#xff0c;发送方和接收方共享一个密钥&#xff0c;数据在传输前被加密&#xff0c;接收方使用相同的密钥…

让Apache正确处理不同编码的文件避免中文乱码

安装了apache2.4.39以后&#xff0c;默认编码是UTF-8&#xff0c;不管你文件是什么编码&#xff0c;统统按这个来解析&#xff0c;因此 GB2312编码文件内的中文将显示为乱码。 <!doctype html> <html> <head><meta http-equiv"Content-Type" c…

SCUI Admin + Laravel 整合

基于 Vue3 和 Element Plus 和 Laravel 整合开发 项目地址&#xff1a;持续更新 LaravelVueProject: laravel vue3 scui

51单片机应用开发(进阶)---定时器应用(电子时钟)

实现目标 1、巩固定时器的配置流程&#xff1b; 2、掌握按键、数码管与定时器配合使用&#xff1b; 3、功能1&#xff1a;&#xff08;1&#xff09;简单显示时间。显示格式&#xff1a;88-88-88&#xff08;时-分-秒&#xff09; 4、功能2&#xff1a;&#xff08;1&#…

移植 AWTK 到 纯血鸿蒙 (HarmonyOS NEXT) 系统 (9) - 编译现有的AWTK应用程序

AWTK 应用程序开发完成后&#xff0c;在配置文件中添加 harmonyos 的选项&#xff0c;通过create_project.py脚本即可生成 DevEco Studio的工程。 安装开发环境 DevEco Studio HarmonyOS 的开发工具。 Python 运行环境。 git 源码管理工具。 下载 awtk 和 awtk-harmonyos…

江苏博才众创科技产业园集团拟投资10亿元在泰兴打造汽车零部件产业园

2024年11月7日&#xff0c;泰兴市高新技术产业开发区与江苏博才众创科技产业园集团举行新能源汽车零部件智能制造产业园项目签约仪式。 泰兴市高新区党工委委员、管理办副主任王峰表示&#xff1a;高新区是全市项目建设的主阵地&#xff0c;近年来聚焦高端化、智能化、绿色化&a…

计算机毕业设计项目推荐,应届毕业生求职网站 80757 上万套实战教程手把手教学JAVA、PHP,node.js,C++、python、大屏

摘要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对应届毕业生求职网站管理等问题&#xff0c;…

OceanBase详解及如何通过MySQL的lib库进行连接

OceanBase详解及如何通过MySQL的lib库进行连接 一、引言二、OceanBase概述1. 起源与发展2. 核心技术特点3. 应用场景三、OceanBase架构解析1. 系统架构2. 存储引擎3. 分布式架构四、如何使用MySQL的lib库连接OceanBase1. 前提条件2. 安装MySQL Connector/C3. 编写连接代码4. 编…

Trimble X12三维激光扫描仪正在改变游戏规则【上海沪敖3D】

Trimble X12 三维激光扫描仪凭借清晰、纯净的点云数据和亚毫米级的精度正在改变游戏规则。今天的案例我们将与您分享&#xff0c;X12是如何帮助专业测量咨询公司OR3D完成的一个模拟受损平转桥运动的项目。 由于习惯于以微米为单位工作&#xff0c;专业测量机构OR3D是一家要求…

UniTask/Unity的PlayerLoopTiming触发顺序

开始尝试在项目中使用UniTask&#xff0c;发现其中的UniTask.Yield确实很好用&#xff0c;还可以传入PlayerLoopTiming来更细致的调整代码时机&#xff0c;不过平常在Mono中接触的只有Awake&#xff0c;Start&#xff0c;Update等常用Timing&#xff0c;其他的就没怎么接触了&a…

分类 classificaton

1&#xff09;什么是分类&#xff1f; 在此之前&#xff0c;我们一直使用的都是回归任务进行学习&#xff1b;这里我们将进一步学习什么是分类&#xff0c;我们先从训练模型的角度来看看二者的区别。 对于回归来说&#xff0c;它所作的是对模型输入相应的特征&#xff0c;然后…

Maven学习——创建Maven的Java和Web工程,并运行在Tomcat上

一、Maven介绍 Maven 是一款为 Java 项目管理构建、依赖管理的工具&#xff08;软件&#xff09;&#xff0c;使用 Maven 可以自动化构建、测试、打包和发布项目&#xff0c;大大提高了开发效率和质量。 二、Maven安装步骤 1.下载后解压到没有空格、特殊字符和中文的目录中 2…

数据血缘追踪是如何在ETL过程中发挥作用?

在大数据环境下&#xff0c;数据血缘追踪具有重要意义&#xff0c;它能够帮助用户了解数据的派生关系、变换过程和使用情况&#xff0c;进而提高数据的可信度和可操作性。通过数据血缘追踪&#xff0c;ETL用户可以准确追溯数据的来源&#xff0c;快速排查数据异常和问题。 一、…

在服务器里安装2个conda

1、安装新的conda 下载地址&#xff1a;Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 本文选择&#xff1a;Anaconda3-2023.03-1-Linux-x86_64.sh 安装&#xff1a;Ubuntu安装Anaconda详细步骤&#xff08;Ubuntu22.04.1&#xff…

OceanBase中,如何解读 obdiag 收集的火焰图 【DBA早下班系列】

1. 前言 在之前的文章 遇到性能问题&#xff0c;如何给OceanBase“拍CT“&#xff08;火焰图与扁鹊图&#xff09;中&#xff0c;分享了obdiag 快速收集火焰图的方法&#xff0c;那么&#xff0c;紧接着的问题便是&#xff1a;收集到火焰图和扁鹊图之后&#xff0c;该如何解读…