2020牛客暑期多校训练营(第八场)I.Interesting Computer Game(map离散化+并查集判环)

地址:https://ac.nowcoder.com/acm/contest/5673/I

题意:

n次,每次给出a,b;

可以进行三种操作:

1.不选

2.a如果之前没选过,可选a

3.b如果之前没选过,可选b

求可以获得的最大数目

解析:

首先用map进行一个离散化处理

假设把每次输入的看成一条边的话,可以推出:

对于每一个并查集块,大小为x,如果内部含环,就是x,否则为x-1

所以用并查集进行判环,c[]进行标记,如果c[]==1,说明它所在块含有环。

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<string.h>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e5+20;
int pr[2*maxn],c[2*maxn];  //假设a[]和b[]每个数都不同,最多需要2*maxn的空间
int a[maxn],b[maxn];
int tot;
int find(int x)
{
    if(x!=pr[x])    return pr[x]=find(pr[x]);
    return x;
}
void init()
{
    for(int i=1;i<=tot;i++)
        pr[i]=i,c[i]=0;
}
int main()
{
    int t;
    scanf("%d",&t);
    int ac=1;
    while(t--)
    {
        int n;
        scanf("%d",&n);
        map<int,int>m;
        tot=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i],&b[i]);
            if(!m[a[i]])m[a[i]]=tot++;
            if(!m[b[i]])m[b[i]]=tot++;
        }
        tot--;
        int sum=tot;
        init();
        for(int i=1;i<=n;i++)
        {
            int x=find(m[a[i]]),y=find(m[b[i]]);
            if(x!=y)
            {
                pr[x]=y;
                if(c[x]||c[y])  //x并到y上,所以它俩只要有环,本并查集块就含环,标记一下。
                    c[y]=1;
            }
            else
                c[y]=1;
        }
    //    cout<<sum<<"-"<<endl;
        for(int i=1;i<=tot;i++)
        {
            if(i==pr[i]&&!c[i])
                sum--;  //非环,--
        }
        printf("Case #%d: %d
",ac++,sum);
    }
}
原文地址:https://www.cnblogs.com/liyexin/p/13434984.html