并查集应用

news2024/9/21 1:42:54

一、并查集模板

int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

 并查集高效率的核心是一旦更新过一次后,就会将路径压缩掉,避免后续重复遍历路径。

二、并查集应用

1、格子游戏

 分析:每构成一个方框,当最后两个点连接时,两个点的祖宗必定是同一个,所以此题就转化为并查集问题,但本题需要把二维坐标转化为一维。

如何把二维坐标转化为一维?

0 1 2   //3X3坐标系转化为一维各个点对应的数值如左图所示
3 4 5   //二维转一维必须从0 0点开始
6 7 8   //如果从1 1点开始,只需x-- y--

//二维坐标(x,y) 对应的数值————> z = x*n+y  , n为坐标系的大小 

代码

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 40010;
int p[N];
int n,m;

int get(int x,int y)
{
    return x*n+y;
}
int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}


int main()
{
    cin>>n>>m;
    for(int i=0;i<n*n;i++) p[i]=i;
    
    int res=0;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        char d;
        cin>>x>>y>>d;
        
        x--,y--;
        int a=get(x,y);
        int b;
        if(d=='D') b=get(x+1,y);
        else b=get(x,y+1);
        
        int pa=find(a),pb=find(b);
        
        if(pa==pb)
        {
            res=i;
            break;
        }
        p[pa]=pb;
    }
    
    if(!res) puts("draw");
    else cout<<res<<endl;
    return 0;
}

2、搭配购买(并查集+01背包)

 分析:云朵绑定购买,相当于把所有绑定的云朵堪为一朵,然后可以买的最大价值,问题转化为利用并查集把绑定的云朵看为一朵,然后01背包求最大价值。

怎样把所有绑定的云朵和价值合并到一块?

利用并查集的思想所有祖宗节点的体积和价值,就可以看为整个连通块的体积和价值。

代码

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 10010;

int v[N],w[N];
int f[N];
int p[N];
int n,m,vol;

int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
int main()
{
    cin>>n>>m>>vol;
    for(int i=1;i<=n;i++) p[i]=i;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    
    //并查集
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin>>a>>b;
        int pa=find(a),pb=find(b);
        
        if(pa!=pb)//祖宗节点对应整个连通块的体积和价值
        {
            v[pb]+=v[pa];
            w[pb]+=w[pa];
            p[pa]=pb;
        }
    }
    
    //01背包
    
    for(int i=1;i<=n;i++)
    {
        if(p[i]==i)
        {
            for(int j=vol;j>=v[i];j--)
            f[j]=max(f[j],f[j-v[i]]+w[i]);
        }
    }
    
    cout<<f[vol]<<endl;
    return 0;
}

3、程序自动分析(离散话+并查集)

 分析:由于 i,j的数据范围较大,所以本题得把数据离散化(映射为1~n的值)

离散化
1.保序离散化(排序+判重+二分)
2.不保序离散化(hash表映射)

本题为不保序离散化,注意初始化1~n的祖宗,n为映射的不同节点的个数

代码

#include<iostream>
#include<algorithm>
#include<unordered_map>

using namespace std;

const int N = 200010;

int p[N];
unordered_map<int,int> S;
int n,m;

struct QUERY{
    int x,y,e;
}query[N];

int get(int x)//不保序离散化
{
    if(S.count(x)==0) S[x]=++n;//判断该数是否存在,n从0开始
    return S[x];
}
int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        n=0; //从0开始
        scanf("%d",&m);
        S.clear();//注意清空
        for(int i=0;i<m;i++)
        {
            int x,y,e;
            scanf("%d%d%d",&x,&y,&e);
            query[i]={get(x),get(y),e};
        }
        
        for(int i=1;i<=n;i++) p[i]=i;
        
        for(int i=0;i<m;i++)
        {
            if(query[i].e==1)
            {
                int pa=find(query[i].x),pb=find(query[i].y);
                p[pa]=pb;
            }
        }
        
        int flag=0;
        for(int i=0;i<m;i++)
        {
            if(query[i].e==0)
            {
                int pa=find(query[i].x),pb=find(query[i].y);
                if(pa==pb)
                {
                    flag=1;
                    break;
                }
            }
        }
        if(flag) puts("NO");
        else puts("YES");
    }
    
    return 0;
}

4、银河英雄传说

 分析:本题为路径维护题,维护子节点到根节点的距离。注意更新祖宗时所更新的所有内容

解题思路:把 i 舰队放到 j 舰队后面的操作:首先找到i与j的祖宗,如果两个祖宗不一样,那么更新

s数组(表示该连通块的大小)d数组(表示每个子节点到祖宗的长度),p数组。

当更新一次d数组后,d[x] = d[x](表示该节点到没更新祖宗前的距离)+d[p[x]](表示该节点到没更新祖宗前的祖宗,到的更新后祖宗的距离)如下图所示

 两个节点之间的距离:abs(d[a]-d[b])-1;当两个节点相同时结果为0,需要用max特判

 代码

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 30010;

int p[N],d[N],s[N];
int n,m;

int find(int x)
{
    if(p[x]!=x)
    {
        int root=find(p[x]);
        d[x]+=d[p[x]];
        p[x]=root;
    }
    return p[x];
}
int main()
{
    int T;
    scanf("%d",&T);
    
    for(int i=1;i<N;i++ )
    {
        p[i]=i;
        s[i]=1;
    }    
    while(T--)
    {
        char op[2];
        int a,b;
        scanf("%s%d%d",op,&a,&b);
        
        if(op[0]=='M')
        {
            int pa=find(a),pb=find(b);
            if(pa!=pb)//注意更新的内容
            {
                d[pa]=s[pb];
                s[pb]+=s[pa];
                p[pa]=pb;
            }
        }
        else
        {
            int pa=find(a),pb=find(b);
            if(pa!=pb) puts("-1");
            else printf("%d\n",max(0,abs(d[a]-d[b])-1));//两点相同时取0
        }
    }
    
    return 0;
}

5.奇偶游戏

 分析:根据前缀和的思想(A只为0或 1 )

假设Si=A1+A2+......+Ai;

那么S[l,r]是奇数就相当于Sr-S(l-1) 中有奇数个1,同理偶数是一样的。

前缀和的思想可以转化为在同一个集合里维护每一个点与祖宗的关系可以推出点与点之间的关系。(d数组的值为1,说明与祖宗关系不同,0说明相同)

如果两个数状态相反,那么说明他们之间有奇数个1.

异或运算相当于不进位加法,并且可以表示在模2的情况下计算

#include<iostream>
#include<algorithm>
#include<string>
#include<unordered_map>
using namespace std;

const int N = 10010;

int n,m;
int p[N];
int d[N];
unordered_map<int,int> S;

int get(int x)
{
    if(S.count(x)==0) S[x]=++n;
    return S[x];
}

int find(int x)
{
    if(p[x]!=x)
    {
        int root=find(p[x]);
        d[x]^=d[p[x]];
        p[x]=root;
    }
    return p[x];
}

int main()
{
    scanf("%d%d",&n,&m);
    n=0;
    
    for(int i=1;i<N;i++) p[i]=i;
    int res=m;
    for(int i=1;i<=m;i++)
    {
        string op;
        int a,b;
        scanf("%d%d",&a,&b);
        cin>>op;
        
        a=get(a-1),b=get(b);
        
        int t=0;
        if(op=="odd") t=1;
        
        int pa=find(a),pb=find(b);
        
        if(pa==pb)
        {
            if((d[a]^d[b])!=t)
            {
                res=i-1;
                break;
            }
        }
        else
        {
            p[pa]=pb;
            d[pa]=d[a]^d[b]^t;
        }
    }
    cout<<endl;
    cout<<res<<endl;
    return 0;
}

(2)合并集合的做法,维护两个集合,同一类的放到一个集合

如果a和b为同一类的话把a的祖先设为b, a+M的祖先设为 b+M

如果a+M和b为同一类的话把a+M的祖先设为b,a的祖先设为b+M

#include<iostream>
#include<algorithm>
#include<string>
#include<unordered_map>
using namespace std;

const int N = 40010,M=N/2;

int n,m;
int p[N];
int d[N];
unordered_map<int,int> S;

int get(int x)
{
    if(S.count(x)==0) S[x]=++n;
    return S[x];
}

int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

int main()
{
    scanf("%d%d",&n,&m);
    n=0;
    
    for(int i=1;i<N;i++) p[i]=i;
    int res=m;
    for(int i=1;i<=m;i++)
    {
        string op;
        int a,b;
        scanf("%d%d",&a,&b);
        cin>>op;
        
        a=get(a-1),b=get(b);
        int pa=find(a),pb=find(b);
        int pa1=find(M+a),pb1=find(M+b);        
        
        if(op=="odd")
        {

   
            if(pa==pb)
            {
                res=i-1;
                break;
            }
            p[pa1]=pb;
            p[pa]=pb1;
        }
        else
        {
            if(pa1==pb)
            {
                res=i-1;
                break;
            }
            p[pa]=pb;
            p[pa1]=pb1;
        }
    }
    
    cout<<res<<endl;
    return 0;
}

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

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

相关文章

RA4M2开发(2)----基于IIC驱动OLED

概述 在e2studio中创建新的工程并导入必要的文件&#xff0c;包括I2C驱动代码和SSD1306 OLED显示驱动代码。配置RA4M2的I2C接口&#xff0c;使其作为I2C master进行通信。初始化SSD1306 OLED显示驱动代码&#xff0c;并配置显示屏的物理地址和分辨率。通过I2C驱动代码将数据写…

【Linux】初识环境变量

文章目录环境变量引入初见环境变量和环境变量有关的指令如何通过代码获取环境变量getenv()main函数的命令行参数第三方变量environ程序变量可以继承给子进程环境变量引入 Linux中有各种指令&#xff0c; 每个指令其实都是一个可执行程序&#xff1a; 和我们自己写的C语言代码…

API自动化测试【postman生成报告】

PostMan生成测试报告有两种&#xff1a; 1、控制台的模式 2、HTML的测试报告 使用到一个工具newman Node.js是前端的一个组件&#xff0c;主要可以使用它来开发异步的程序。 一、控制台的模式 1、安装node.js 双击node.js进行安装&#xff0c;安装成功后在控制台输入node…

Ansys Zemax | 多模光纤耦合

本文展示了利用几何图像分析特性来计算多模光纤耦合效率的方法。 还有使用IMAE操作数优化多模光纤耦合效率的方法。该方法只适用于包含大量模式的多模光纤。 下载 联系工作人员获取附件 简介 我们可以使用OpticStudio中的几何图像分析&#xff08;Geometric Image Analysi…

已解决error: legacy-instal1-failure

已解决&#xff08;pip install wxPython安装失败&#xff09;error: legacy-instal1-failure Encountered error while trying to install package.wxPython note: This is an issue with the package mentioned above&#xff0c;not pip. hint : See above for output from …

ChatGPT 回答什么是敏捷测试

Jenkins 官方文档&#xff1a;https://jenkins.io/doc/JUnit 插件文档&#xff1a;JUnit | Jenkins pluginTestNG 插件文档&#xff1a;https://plugins.jenkins.io/testng-plugin/Jenkins 教程&#xff1a;https://jenkins.io/doc/tutorials/JUnit 教程&#xff1a;JUnit 5 Us…

舆情监测软件报价方案,TOOM舆情监控软件多少钱?

舆情监测软件的价格因公司不同而有所差异&#xff0c;通常在几百元至数千元不等。价格还可能受到功能复杂度、数据量、使用时长等因素的影响。建议您联系多家软件开发商或销售代表&#xff0c;对比各家的产品和报价&#xff0c;以找到适合您需求和预算的解决方案。舆情监测软件…

算法训练营DAY46|139.单词拆分、多重背包的介绍

这一期到了背包问题的最后一期&#xff0c;主要讲解一道leetcodee题&#xff0c;和对多重背包的一些简单介绍&#xff0c;由于leetcode没有对于多重背包的具体问题&#xff0c;且面试基本不会问到多重背包所以只是作为科普。 139. 单词拆分 - 力扣&#xff08;LeetCode&#x…

缺省参数,函数重载,引用的使用(C++)

前言 本文主要讲解的是缺省参数&#xff0c;函数重载&#xff0c;引用的使用. 文章目录 目录 前言 一、缺省参数是什么&#xff1f; 1.缺省参数的分类 二、函数重载是什么&#xff1f; 三、引用是什么&#xff1f; 1.引用特性 总结 提示&#xff1a;以下是本篇文章正文内容&am…

java中的NIO,BIO,AIO

IO&#xff0c;input和output&#xff0c;Java 为 I/O 提供了强大的而灵活的支持&#xff0c;使其更广泛地应用到文件传输和网络编程中。 IO是什么&#xff1f;为什么需要IO&#xff1f; java在1.4之前&#xff0c;提供的是BIO&#xff0c;也就是java.io包下的的东西&#xf…

SpringBoot(二):配置文件的作用、配置文件的格式、properties配置文件、yml配置文件

目录一、配置文件的作用二、配置文件的格式三、properties配置文件3.1 properties的基本语法3.2 properties的缺点3.3 配置自定义内容3.4 读取配置文件四、yml配置文件4.1 yml基本介绍4.2 yml基本语法4.3 使用yml配置不同的数据类型4.4 读取yml配置文件4.5 在yml中配置对象4.6 …

关于UWB汽车钥匙介绍

汽车钥匙经历了机械钥匙、遥控钥匙、PEPS、数字钥匙四个阶段&#xff0c;而数字钥匙又分为BLE/NFC/UWB三种技术路线。由于UWB安全性、定位精度、作用范围明显好于BLE和NFC&#xff0c;因此成为汽车数字钥匙的最优技术。PEPS与数字钥匙PEPS是指无钥匙进入/无钥匙启动系统&#x…

MySQL详解(三)——高级 1.0

MySQL高级 utf8只支持每个字符最多三个字节&#xff0c;而真正的 UTF-8 是每个字符最多四个字节 MySQL 的这个bug一直没有被修复&#xff0c;他们在 2010 年发布了一个叫作“utf8mb4”的字符集&#xff0c;绕过了这个问题。 MySQL优点 Mysql是开源的Mysql是可以定制的&…

CDN的那些事

CDN的那些事一、前言二、基础配置三、访问控制四、缓存配置五、HTTPS配置六、高级配置&#xff08;最重点来了&#xff09;七、结语一、前言 大家好&#xff0c;我是尝试中成长的站长&#xff0c;前段时间&#xff0c;群友的cdn被刷爆了&#xff0c;这就引起了我的恐慌&#x…

读书笔记:神经网络加法层与乘法层的实现及应用 buy_apple_orange.py ← 斋藤康毅

“层”是神经网络中功能的单位。通常把神经网络的“层”实现为一个类。“层”的实现中有两个共通的方法 forward() 和 backward()。forward() 对应正向传播&#xff0c;backward() 对应反向传播。加法结点的反向传播将上游的值原封不动地输出到下游&#xff0c;乘法结点的反向传…

第2章:使用CSS定义样式

在前一章中,我们研究了Java代码的不同片段。 在本章中,我们将对每个示例使用相同的代码段: public void createPdf(String html, String dest) throws IOException {HtmlConverter.convertToPdf(html, new FileOutputStream(dest)); } 我们不看Java代码的不同片段,而是看…

数据分析-深度学习Pytorch Day13

单层感知机和多层感知机(MLP)是最基础的神经网络结构。将卷积操作创新的加入到神经网络结构形成了卷积神经网络&#xff0c;卷积神经网络给现代人工智能注入了活力。感知机网络和卷积网络(CNN)都属于前馈型网络(FeedForward Network)。单层感知机是二分类的线性分类模型&#x…

MT1010-M1016(java版)

MT1010输入和输出字符型数据难度&#xff1a;青铜0时间限制&#xff1a;1秒巴占用内存&#xff1a;64M★收藏△报错请编写一个简单程序&#xff0c;用户输入2个的字符型数据存储在变量中&#xff0c;并分别以字符形式和整数形式输出在屏幕上。格式输入格式&#xff1a;2个的字符…

Go语言DDD实战初级篇

导读 领域驱动设计(DDD)最简洁的描述可能是&#xff1a;如何在明确的限界上下文中创建通用语言的模型。通过 DDD思想设计开发的软件&#xff0c;在领域专家、开发者和软件本身之间不存在“翻译”&#xff0c;三者通过在限界上下文下的通用语言直接表示。而这个系列则是我们团队…

交换机——VLAN原理和基本配置

VLAN原理和配置VLAN的三种端口类型Access&#xff1a;接入链路类型&#xff08;一般使用&#xff1a;交换机与PC&#xff09;Trunk&#xff1a;干道链路类型&#xff08;一般使用&#xff1a;交换机与交换机&#xff09;Hybrid在这里&#xff0c;我们只使用和讲解Access和Trunk…