2020-08-17

P3367 【模板】并查集

在这里插入图片描述

基本原理:每个集合用一个树来表示。树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点。

#include<iostream>
#include<algorithm>
#include<stdio.h>

using namespace std;

const int N = 10010;

int p[N];//表示父节点

int find(int x)// 找到x的祖宗节点 + 把路径上所有点的父节点变为祖宗节点
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
    
}

int main()
{
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; i ++)  p[i] = i;//初始化,一开始时每个点单独为一个集合
    
    while(m --)
    {
        int a, b, c;
        cin >> a >> b >> c;
        if(a == 1)
        {
            p[find(b)] = find(c);//将b的祖宗节点的父节点变为c的祖宗节点,就将两个集合合并了
        }
        else
        {
            if(find(b) == find(c)) puts("Y");
            else puts("N");
        }
    }
    return 0;
}

P1551 亲戚

在这里插入图片描述
基本原理:每个集合用一个树来表示。树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点。

#include<iostream>
#include<algorithm>
#include<stdio.h>

const int N = 5005;

int q[N];

using namespace std;

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

int main()
{
    int n, m, p;
    cin >> n >> m >> p;
    for(int i = 1; i <= n; i ++) q[i] = i;//有n个人,最初每个人是单独的,互相没有关系。
    while(m --)
    {
        int a, b;
        cin >> a >> b;
        q[find(a)] = find(b);//将a的祖宗节点的父节点变为b的祖宗节点,就使之成为一个集合。
    }
    
    while(p --)
    {
        int c, d;
        cin >> c >> d;
        if(find(c) == find(d)) puts("Yes");//祖宗节点相同
        else puts("No");
    }
    return 0;
}

P2256 一中校运会之百米跑

在这里插入图片描述
在这里插入图片描述
基本原理:每个集合用一个树来表示。树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点。

唯一难点是字符串的处理,关于字符串处理,c++里有个库函数叫map,map<string, string> p,就相当于定义一个类型为字符串, 下标为字符串的数组p。

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<map>

using namespace std;

map<string, string> p;

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

int main()
{
    int n, m, k;
    cin >> n >> m;
    
    while(n --)
    {
        string x;
        cin >> x;
        p[x] = x;
    }
    
    while(m --)
    {
        string a, b;
        cin >> a >> b;
        p[find(a)] = find(b);
    }
    cin >> k;
    while(k --)
    {
        string c, d;
        cin >> c >> d;
        if(find(c) == find(d)) puts("Yes.");
        else puts("No.");
    }
    return 0;
}

P1536 村村通

在这里插入图片描述

基本原理:每个集合用一个树来表示。树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点。

思路:将用已有道路连接的城镇放在一个集合,然后统计有多少个不同的集合。

#include<iostream>
#include<algorithm>
#include<stdio.h>

using namespace std;

const int N = 1010;

int p[N], q[N];


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

int main()
{
    int n, m;
    while(1)
    {
        scanf("%d", &n);
        if(n == 0) break;
        scanf("%d", &m);
        for(int i = 1; i <= n; i ++)
        {
            p[i] = i;
        }
    
        while(m --)
        {
            int x1, x2;
            cin >> x1 >> x2;
            if(find(x1) != find(x2))
            {
                p[find(x1)] = find(x2);
            }
        }
        int sum = 0;
        for(int i = 1; i <= n; i ++)
        {
            q[i] = find(i);//将每一个点的祖宗节点重新用一个新的数组存储。
        }
        //去掉q数组中重复的数
        for(int i = 1; i <= n; i ++)
        {
            for(int j = i + 1; j <= n; j ++)//从i后面的一个元素开始寻找。
            {
                if(q[j] == q[i])//如果发现重复。
                {
                    for(int k = j + 1; k <= n; k ++)
                    {
                        q[k - 1] = q[k];//将后面的数依次赋值给前面一个位置。
                    }
                    n --;//数组长度减1.
                    j --;//重复点再次进行查重。
                }
            }
        }
        for(int i = 1; i <= n; i ++)
        {
            if(q[i] != 0)
            sum ++;//统计共有多少个集合。
        }
        cout << sum - 1 << endl;
    }
        return 0;
}

P2814 家谱

在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<map>


using namespace std;

map<string, string> p;

string find(string x)
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}
int main()
{
    string a, b;
    char ch;
    cin >> ch;
    while(ch != '$')
    {
        cin >> a;
        if(ch == '#')
        {
            b = a;//当每次输入的是#时,b存储的是当前所输入的父亲而不是之前输入的父亲。
            if(p[a] == "") p[a] = a;//当a是最早的祖先时,就使p[a]等于自己。
        }
        else if(ch == '+')
        {
            p[a] = b;//a的父亲为b。
        }
        else
        {
            cout << a << ' ' << find(a) << endl;
        }
        cin >> ch;
    }
    return 0;
}

P2078 朋友
在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<stdio.h>

using namespace std;

const int N = 20010;//n + m的数据范围

int a[N],cnt[N];

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

int main()
{
    int n, m, p, q;
    cin >> n >> m >> p >> q;
    
    for(int i = 1; i <= n + m; i ++)//n + 1往后是存储的女生
    {
        a[i] = i, cnt[i] = 1;
    }
    
    while(p --)
    {
        int x1, x2;
        cin >> x1 >> x2;
        if(find(x1) != find(x2))
        {
            cnt[find(x2)] += cnt[find(x1)];
            a[find(x1)] = find(x2);
        }
    }
    
    while(q --)
    {
        int x1, x2;
        cin >> x1 >> x2;
        
        if(find(n - x1) != find(n - x2))//因为x1,x2是负数,用n来减得到存储的下标。
        {
            cnt[find(n - x2)] += cnt[find(n - x1)];
            a[find(n - x1)] = find(n - x2);
        }
    }
    //统计find(1)与find(n + 1)中各自的人数,其中最小的就是结果。
    int t = cnt[find(1)], h = cnt[find(n + 1)];
    if(t <= h) cout << t;
    else cout << h;
    return 0;
    
    
}

P6121 [USACO16OPEN]Closing the Farm G
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值