1. 程式人生 > 實用技巧 >2020牛客多校第八場I題Interesting Computer Game(並查集求連通分量)

2020牛客多校第八場I題Interesting Computer Game(並查集求連通分量)

題目連結https://ac.nowcoder.com/acm/contest/5673/I

題意:輸入n對數,選n次,你每次可以從一對數中選一個,輸出最多可以選到多少個不同的數。

題解:如果我們把每個數字當做點,n對數當做邊,我們可以建立一個圖,求這個圖的連通分量,判斷連通分量是否是環,如果是環ans+=這個連通塊大小 ,如果不是環ans+=這個連通塊大小-1。這樣的思路我們可以用帶權並查集實現,size表示連通區塊的大小,vis表示該連通區塊是不是環。因為該題數字的範圍大,所有我們要先進行離散化。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using
namespace std; typedef long long ll; const int maxn=5e5+7; const ll mod =1e9+7; int a[maxn],b[maxn]; int fa[maxn],size[maxn],vis[maxn]; int n,t; vector<int> p; ll ans; int find_fa(int x){ if(fa[x]==x) return x; else return fa[x]=find_fa( fa[x]); } int get_id(int x){ return lower_bound(p.begin(),p.end(),x)-p.begin()+1
; } int main(){ scanf("%d",&t); int k=1; while(t--){ scanf("%d",&n); for(int i=1;i<=2*n+7;i++){ fa[i]=i; size[i]=1; vis[i]=0; } for(int i=1;i<=n;i++){ scanf("%d%d",&a[i],&b[i]); p.push_back(a[i]); p.push_back(b[i]); } sort(p.begin(),p.end());
//離散化 p.erase( unique(p.begin(),p.end()),p.end() ); int m=p.size(); ans=0; for(int i=1;i<=n;i++){ int ida=get_id(a[i]); int idb=get_id(b[i]); int aa=find_fa( ida ); int bb=find_fa( idb ); // cout<<"! "<<aa<<" "<<bb<<endl; if(aa!=bb){ fa[aa]=bb; size[bb]+=size[aa]; vis[bb]=vis[aa]|vis[bb]; }else{ vis[aa]=1; } } for(int i=1;i<=m;i++){ int faz=find_fa(i); if(vis[faz]) ans++,vis[faz]=0; if(fa[i]==i) ans+=size[i]-1; } printf("Case #%d: %d\n",k++,ans); p.clear(); } return 0; }