Interesting Computer Game【并查集】-2020牛客暑期多校8

题意:

一个游戏有 (n) 个回合,每个回合给出两个数 (a_i)(b_i),每个回合可以选择一个之前没有选择过的数或者不选。现在知道了每个回合给的数是多少,求可以选择的最多的数的数量。
(1leq N leq 10^5,1leq a_i leq 10^9,1 leq b_i leq 10^9)
题目链接:https://ac.nowcoder.com/acm/contest/5673/I

分析:

解法1:【并查集】

首先,对每个回合给出的数进行离散化。对于在同一个回合给出的数,将两个数并在一起。对于一个联通块而言,如果其中没有环的话,一定存在一种选取方式,使得最后联通块中只剩下一个点没有被选择。因此,可以选择的数的数量就是联通块点数 (-1)。对于存在环的联通块而言,一定存在一种方式,使得可以将所有的点全部取完。所以,用并查集求出联通块的数量并标记是否有环即可。

代码1:

#include <bits/stdc++.h>

using namespace std;
const int N=1e5+5;
int num[N<<1],len,a[N],b[N],fa[N<<1];
bool vis[N<<1];
int getid(int x)
{
    return lower_bound(num+1,num+1+len,x)-num;
}
int Find(int x)
{
    if(x!=fa[x])
        return fa[x]=Find(fa[x]);
    else return x;
}
int main()
{
    int T,cas=0,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i],&b[i]);
            num[++cnt]=a[i];
            num[++cnt]=b[i];
        }
        sort(num+1,num+1+cnt);
        len=unique(num+1,num+1+cnt)-num-1;
        for(int i=1;i<=len;i++)
        {
            fa[i]=i;
            vis[i]=false;
        }
        for(int i=1;i<=n;i++)
        {
            int x=getid(a[i]);
            int y=getid(b[i]);
            int fx=Find(x),fy=Find(y);
            if(fx!=fy)
            {
                fa[fy]=fx;
                if(vis[fx]||vis[fy])//存在环,把标记转移到祖先
                    vis[fx]=1,vis[fy]=0;
            }
            else vis[fx]=1;//祖先标记联通块
        }
        int ans=len;
        for(int i=1;i<=len;i++)
        {
            if(fa[i]==i&&!vis[i]) ans--;
        }
        printf("Case #%d: %d
",++cas,ans);
    }
    return 0;
}

解法2:

将每组 (a_i,b_i) 两个数连上一条边,这道题就可以转化成一个图的问题:给定一张点权图,对于图中每条边可以选择两个顶点中的一个,求最多可以选多少个值不同的点。显然,所有的 (a_i)(b_i) 所构成的图,肯定是由若干连通的块组成的。对每个连通块考虑,设一个连通块有 (n) 个点,它最少有 (n-1) 条边,在这种情况下,最多可以选的点数是 (n-1) 个;而在边多于 (n-1) 时,我们就可以选全部的 (n) 个点。如果把这个图想象成一个有根树,在边数大于 (n-1) 条时,我们在多出的边中随便选一条,在这条边定一个根,就可以选根了。
综上,我们这个问题就转化为了:
在每个连通图中,边的数量大于 (n-1) 条就选 (n) 个,否则选 (n-1) 个,统计所有图之和。

参考:
https://ac.nowcoder.com/acm/discuss/blogs?tagId=137444

原文地址:https://www.cnblogs.com/1024-xzx/p/13429559.html