题意:
有n轮游戏,每轮你可以从二个数中选择其中一个数,求你选择数的种类最多为多少?
思路:
先离散化数据,然后我们将每一轮游戏当成一条边,如果成环了,则该环所以端点都能选择,且与环连通的点也能全部选择,你画个图就很容易理解了,由环往外扩散。如果连通块无环,则有一个端点无法选择。所以我们用并查集来处理数据,有环则给该连通块做个标记。
代码:
#include <bits/stdc++.h> typedef long long ll; using namespace std; const int inf=1000000007; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } struct w { int x, y; } w[100005]; int ma[200005], ran[200005], shu[200005], ans, pre[200005], fu[200005]; map<int,int> mp; bool cmp(struct w a,struct w b) { return a.y<b.y; } void inti(int k) { for(int i=1;i<=k;i++) { pre[i]=i; ran[i]=0; } } int find(int x) { if(pre[x]==x) { return x; } return pre[x]=find(pre[x]); } int unite(int x,int y) { x=find(x); y=find(y); if(x!=y) { fu[y]=fu[y]|fu[x]; fu[x]=fu[x]|fu[y]; if(ran[y]>ran[x]) { pre[x]=y; } else { if(ran[x]==ran[y]) { ran[x]++; } pre[y]=x; } } } bool same(int x,int y) { return find(x)==find(y); } int main() { int t; t=read(); for(int o=1; o<=t; o++) { int n, ji=0; n=read(); memset(fu,0,sizeof(fu)); memset(ma,0,sizeof(ma)); ans=0; for(int i=0; i<n; i++) { w[i].x=read(); w[i].y=read(); shu[ji++]=w[i].x; shu[ji++]=w[i].y; } sort(shu,shu+ji); int k=1; for(int i=0; i<ji-1; i++) { if(shu[i]!=shu[i+1]) { k++; mp[shu[i]]=k-1; } } mp[shu[ji-1]]=k; k++; inti(k); for(int i=0; i<n; i++) { w[i].x=mp[w[i].x]; w[i].y=mp[w[i].y]; if(same(w[i].x,w[i].y)) { fu[find(w[i].x)]=1; } else { unite(w[i].x,w[i].y); } } for(int i=1; i<k; i++) { ma[find(i)]++; } for(int i=1; i<k; i++) { if(ma[i]>0) ans=ans+ma[i]+fu[i]-1; } mp.clear(); printf("Case #%d: %d\n",o,ans); } return 0; }