Invoking the Magic Gym - 102770I(并查集+离散化)

本文通过一道关于袜子配对的问题,介绍了一种结合并查集和离散化的算法应用。题目要求在限制容量的魔法洗衣盆中,找到最小的容量以成功配对所有袜子。通过证明袜子能形成环,并使用并查集维护集合大小,配合离散化处理大量数据,最终找到最大集合大小作为答案。代码中展示了具体实现过程,包括离散化、并查集操作和集合大小更新。
摘要由CSDN通过智能技术生成

@[TOC](Invoking the Magic Gym - 102770I(并查集+离散化))

BaoBao is a lazy boy. He has nn pairs of socks in different colours and he washes them once a month. In the washing machine, these socks will be mixed.

Because there are too many socks that need to be paired, BaoBao divides the whole sock pairing process into two stages.

In the first stage, BaoBao randomly distributes the socks in pairs. Then in the second stage, BaoBao repeats the following operation until all the socks are paired: BaoBao chooses some of the pairs of socks, puts them into his magic washing basin, and uses his magic. If the socks in the magic washing basin can be paired perfectly when he uses his magic, the magic washing basin will pair them for BaoBao automatically. However, if they can’t (which means there is at least one sock whose colour is unique in the basin), the magic basin will explode and BaoBao must not let this happen.

BaoBao’s magic is limited, after the first stage, he needs to know the minimum capacity of the magic washing basin that he needs to pair all the socks successfully. The capacity of the basin is the maximum number of pairs of socks BaoBao can put in the magic washing basin at one time.

Input
The input contains multiple cases. The first line of the input contains a single positive integer TT (1≤T≤101≤T≤10), the number of cases.

For each case, the first line of the input contains a single integer n (1≤n≤105)n (1≤n≤105), the number of pairs of socks.

For the following nn lines, the ii-th (1≤i≤n1≤i≤n) line contains two integers aiai and bibi (1≤ai,bi≤230)(1≤ai,bi≤230), denoting the colours of the two socks in the ii-th pair after the first stage. It is guaranteed that for each sock, there is exactly one other sock of the same colour.

Output
For each case, print a single line containing a single integer, the minimum capacity of the magic washing basin.

Example
Input
1
5
1 2
2 3
1 3
4 5
4 5
Output
3
Note
In the sample, BaoBao can first put these three pairs of socks: {1,2}{2,3}{1,3} in the magic washing basin and then they will be paired into {1,1}{2,2}{3,3}. Then, he can put {4,5}{4,5} in the magic washing basin and they will be paired into {4,4}{5,5}. Therefore, with a capacity of 33 it is possible to pair all the socks successfully. It can be shown by brute-force that this is impossible with a capacity of 22.

写这道题主要是保存一下并查集的变式和离散化的写法 这道题的思路还是很明晰的
题目大意就不过多介绍了,就介绍一下做法。因为袜子是成双的,所以可以证明肯定是能成环的,这道题就是让你找出最大的环。并且,可以证明,只要两个是给出的成对的,那就必然在一个环里,而且两个环之间不能交叉,那么就能很快想到了并查集算法(很快想到dfs也是可能的,不过能不暴力就不暴力) 那么想到这里就有两件事需要解决了,一是有1e5(1*10^5)个数,却在1e9的区间里,二是要计算每个集合的大小,再取最大值。
对于一,我们很快就能想出来用离散化,但是离散化又不是很好写,第二么,我们可以再额外开一个数组储存每个集合的大小,把它保存在每个集合的老大那里,当两个集合合并时就同时把老大手底下的人数也给过去 就行了
需要注意的是,我们要寻找集合的最大值,我给出的方法是当集合合并的时候就更新一下
对了,这道int就能过,用long long会增加时间(约200ms)
代码如下

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;

int pre[maxn];
int num[maxn];//用来并茶几和保存个数

int a[maxn];
int b[maxn];
int s[maxn];//三个数组用来离散化
int n, tot;
int maxx;
int findd(int x)
{
    int f = x;
    while(x != pre[x])
        x = pre[x];
    return f = pre[x];
}
void unionn(int x, int y)
{
    int xx = findd(x);
    int yy = findd(y);
    if(xx != yy)
    {
        pre[xx] = yy;
        num[yy] += num[xx];
        maxx = maxx > num[yy] ? maxx : num[yy];
        num[xx] = 0;//这里不归零也对
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        maxx = -1;
        tot = 0;
        scanf("%d", &n);
        for(int i=0; i<n; i++)
        {
            scanf("%d %d", &a[i], &b[i]);
            s[tot++] = a[i];
            s[tot++] = b[i];
        }
        sort(s, s+tot);
        tot = unique(s, s+tot) - s;//删除相同的元素
        for(int i=0; i<=tot; i++)
        {
            pre[i]=i;
            num[i]=1;
        }
        for(int i=0; i<n; i++)
        {
            int u = lower_bound(s, s+tot, a[i]) - s;//第几个元素(相当于离散化之后的)
            int v = lower_bound(s, s+tot, b[i]) - s;
            unionn(u, v);
        }
        printf("%d\n", maxx);
    }
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值