zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    win10如何安装应用商店
    Redis从入门到精通——认识 Redis
    SkyWalking——SkyWalking安装和配置
    SkyWalking——SkyWalking二次开发必备知识
    SkyWalking——SkyWalking架构设计
    SkyWalking——全面认识Apache SkyWalking
    Redis从入门到精通——初识NoSQL
    RocketMQ(4.8.0)——延迟消息机制
    RocketMQ(4.8.0)——事务消息机制
    RocketMQ(4.8.0)——Broker 的关机恢复机制
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/13429559.html
Copyright © 2011-2022 走看看