1. 程式人生 > 實用技巧 >2020牛客暑期多校訓練營(第八場)I.Interesting Computer Game(map離散化+並查集判環)

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\n",ac++,sum); } }