题意:
有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;
}

京公网安备 11010502036488号