并查集题目整理

并查集

之前写最小生成树的时候对这一部分的知识也并没有十分详细的整理

近天做了一些用到并查集的题目,来整理一下

知识回顾

首先,先来回顾一下有关并查集的内容

<1> 定义

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。

集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

<2>初始化

把每个点所在集合初始化为其自身。

通常来说,这个步骤在每次使用该数据结构时只需要执行一次,无论何种实现方式,时间复杂度均为O(N)。

<3>查找

查找元素所在的集合,即根节点。

<4>合并

将两个元素所在的集合合并为一个集合。

通常来说,合并之前,应先判断两个元素是否属于同一集合,这可用上面的"查找"操作实现。

主要处理的是有关这一部分的两个例题

Luogu P1550 [USACO08OCT]Watering Hole G

解题思路:

这个题给我的第一印象是最小生成树的Kruscal

但是仔细一读题发现其实有许多小的细节与最精简的Kruscal是有差别的

例如题目中有一个挖井的操作

那就讲问题拆开来看

part1:如何解决连牧场的操作

这里不难想到去直接最小生成树维护

很显然牧场之间的连线满足生成树的性质

part2:如何解决挖井的问题

考虑在不影响part1的前提下实现

既然每个牧场挖井都有一定的价格

不难发现这类似于每个牧场与井的连线的价格

考虑将每个牧场与井连线

将井作为单独的第n+1个点去考虑

直接与part1的最小生成树一起操作

代码

#include<bits/stdc++.h>
using namespace std;
struct edge
{
    int from,to,dis;
}e[500001];
bool cmp(edge a,edge b)
{
    return a.dis<b.dis;
}
int father[200001],w[200001];
int getfather(int x)
{
    if(father[x]==x)
        return x;
    father[x]=getfather(father[x]);
    return father[x];
}
int n,cnt,sum;
long long ans;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>w[i];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            sum++;
            e[sum].from=i;
            e[sum].to=j;
            cin>>e[sum].dis;
        }
    for(int i=1;i<=n;i++)
    {
        sum++;
        e[sum].from=i;
        e[sum].to=n+1;
        e[sum].dis=w[i];
    }
    for(int i=1;i<=n+1;i++)
        father[i]=i;
    sort(e+1,e+sum+1,cmp);
    for(int i=1;i<=sum&&cnt<=n;i++)
    {
        int fu=getfather(e[i].from),fv=getfather(e[i].to);
        if(fu==fv)
            continue;
        father[fu]=fv;
        cnt++;
        ans+=e[i].dis;
    }
    cout<<ans;
    return 0;
}

Luogu P2078 朋友

解题思路:

主要还是考虑女士为负数

轻松想到了map,它可以定义任意类型下标

当然也可以将他通过奇妙的操作变为正数,比如加2n来与n进行区分,大致思路没有任何区别

我们发现每个公司都只有同性,那肯定是俩公司一起搭配。

通过这俩人配怎么办?

并查集!每个公司中分别找和这个公司中的媒人祖先相同的点,统计一下个数,最后俩数取小

通俗一点就是将两个公司认识(直接或间接【并查集】)小明或小红的人数统计

最后取min就可以了,毕竟是一夫一妻制

代码:

#include<bits/stdc++.h>
using namespace std;
int n,z,x,y,m,b,q;
map<int,int>fa;
void init()
{
    for(int i=-1*m;i<=n;i++)
        fa[i]=i;
}
int get(int x)
{
      if(fa[x]==x)
          return x;
      int r=get(fa[x]);
      fa[x]=r;
      return r;
}
void merge(int x,int y)
{
    int r1=get(x);
    int r2=get(y);
    if(r1==r2)
        return;
    fa[r1]=r2;
}
int main()
{
    cin>>n>>m>>b>>q;
    init();
    merge(1,-1);
    for(int i=1;i<=b+q;i++)
    {
        cin>>x>>y;
        merge(x,y);
    }
    int ans=0,an=0;
    for(int i=1;i<=n;i++)
        if(get(1)==get(fa[i]))
            ans++;
    for(int i=-1*m;i<0;i++)
        if(get(-1)==get(fa[i]))
            an++;
    cout<<min(ans,an)<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/gongcheng456/p/12628386.html

时间: 2024-11-13 22:30:55

并查集题目整理的相关文章

【并查集题目总结】

[并查集题目总结] 问题一:并查集森林的连通分支数(经典,pre[ i ] == i ?) http://acm.hdu.edu.cn/showproblem.php?pid=1232 问题二:并查集森林所有连通分支最大元素个数(维持一个cnt[ ]数组) http://acm.hdu.edu.cn/showproblem.php?pid=1856 问题三:构造并查集森林过程中计数不能成环的边数(成环 等价于 根节点相同) http://acm.hust.edu.cn/vjudge/proble

并查集题目从入门到入土

2017-09-01 并查集一个神奇的算法 今天我们的s同学想学习一下并查集,就去找了几个水题刷一下... 入门题_1:P2839 畅通工程 畅通工程 就是求联通块的数量,-1就是答案. #include<iostream> #include<cstdio> #include<cstdlib> using namespace std; int read(){ int f=1,an=0; char ch=getchar(); while(!('0'<=ch&

poj 1611 :The Suspects经典的并查集题目

Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others.   In the Not-Spr

并查集题目

POJ 1611 The Suspects 题意是n个人,m组数,每组数的第一个数k表示这组数有k个数,求所有与0直接或间接有关系的数. 建立它们之间的关系后,只要查询下最终的根是0的个数就行,当然两个数中只能最小的数当根. 代码如下: 1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 const int maxn = 3e4+10; 5 int fa[maxn], rank[maxn]; 6 in

684. 冗余连接——经典并查集题目

684. 冗余连接 在本问题中, 树指的是一个连通且无环的无向图. 输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, ..., N) 的树及一条附加的边构成.附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边. 结果图是一个以边组成的二维数组.每一个边的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v的无向图的边. 返回一条可以删去的边,使得结果图是一个有着N个节点的树.如果有多个答案,则返回二维数组中最后出现的边.答案边 [u, v] 应满足相同的

POJ 1182 食物链 (带权并查集 &amp;&amp; 向量偏移)

题意 : 中文题, 直接去POJ  1182看即可 分析 : 通过普通并查集的整理归类, 能够单纯地知道某些元素是否在同一个集合内.但是题目不仅只有种类之分, 还有种类之间的关系, 即同类以及吃与被吃, 而且重点是题目问的并不是种类是否在一个集合内, 而是考察给出的关系是否矛盾.在解释之前, 先明白一个问题, 对于给出的关系, 如果我不能通过前面的信息来推断出来, 是不是不能够判断现在给出关系的对错?那就将这个信息作为真命题并存储起来, 方便后面判断.有了刚刚前面的陈述, 可以知道两个东西=>

HDU3234&amp;&amp;UVA12232&amp;&amp;LA4487:Exclusive-OR(经典带权并查集)

Problem Description You are not given n non-negative integers X0, X1, ..., Xn-1 less than 220 , but they do exist, and their values never change. I'll gradually provide you some facts about them, and ask you some questions. There are two kinds of fac

HDU 并查集 - 3172 Virtual Friends

并查集题目,并的意思就是将两个不同类别的集合合并到一起,类似于两棵树合并:查的意思就是找到这个点所属集合的根节点.基本上并查集题目都是在大体架构上面加一些东西即可.并查集代码模板在这里点击打开链接. 这一题为了找到输入的两个人组成的社交网络人数,也就是统计这两个人与前面的人组成的集合中有多少元素.我们加一个辅助数组sum,当两个集合并时,我们将父节点对应下标的sum值加上子节点的sum值,表达这个集合有多少元素. #include<stdio.h> #include<iostream&g

hdu 1829 A Bug&#39;s Life (基础并查集)

题目: 链接:点击打开链接 题意: 给定虫子的交配关系,确定实验是否支持教授的假设即没有同性恋或者不符合假设. 思路: 是一道基础的并查集题目.存在两个集合异性和同性,给出多组关系,看这两个集合有木有联系,即是否有同性恋. 定义一个数组sex[],sex[i]表示与编号i的性别相反的虫子编号.然后将和i虫子有联系的合并为同一个集合(认为是同性的).如果findset(u) == findset(v),出现了反常行为. 代码: #include <iostream> #include <c