并查集入门水题练习:
POJ1611 The Suspects
http://poj.org/problem?id=1611
题意还是很好理解的:
给定一定的关系,输出与0有关的人。。。
明显是并查集裸题,模板题
#include<cstdio>
#include<cstring>
#define MAXN 30000+5
int rank[MAXN],num[MAXN],fa[MAXN],n,m;
int find(int a)
{
if(fa[a]==a)
return a;
else
return fa[a]=find(fa[a]);
}
void init()
{
for(int i=0;i<=n;i++)
{
rank[i]=0;
fa[i]=i;
num[i]=1;
}
}
void unite(int a,int b)
{
a=find(a);
b=find(b);
if(a==b)
return ;
if(rank[b]>rank[a])
{
fa[a]=b;
num[b]+=num[a];
num[a]=num[b];
}
else
{
fa[b]=a;
num[a]+=num[b];
num[b]=num[a];
if(rank[a]==rank[b])
rank[a]++;
}
}
int main()
{
int k,t,p;
while(1)
{
scanf("%d%d",&n,&m);
if(!n&&!m)
break;
init();
for(int i=1;i<=m;i++)
{
scanf("%d",&k);
if(k)
scanf("%d",&t);
for(int j=1;j<=k-1;j++)
{
scanf("%d",&p);
unite(p,t);
}
}
printf("%d\n",num[find(0)]);
}
return 0;
}
HDU1213 How Many Tables
http://acm.hdu.edu.cn/showproblem.php?pid=1213
给定n个人的关系,输出有关系的人坐在一桌上,判断一共需要多少桌
有一个模板题。。。
用并查集合并,最后寻找有几个祖先就行了
#include<cstdio>
#define MAXN 1005
int fa[MAXN],rank[MAXN],n;
int find(int a)
{
if(fa[a]==a)
return a;
else
return fa[a]=find(fa[a]);
}
void unite(int a,int b)
{
a=find(a);
b=find(b);
if(a==b)
return ;
if(rank[a]<rank[b])
fa[a]=b;
else
{
fa[b]=a;
if(rank[a]==rank[b])
rank[a]++;
}
return ;
}
void init()
{
for(int i=1;i<=n;i++)
{
fa[i]=i;
rank[i]=0;
}
}
int main()
{
int T,a,b,m;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
unite(a,b);
}
int ans=0;
for(int i=1;i<=n;i++)
if(find(i)==i)
ans++;
printf("%d\n",ans);
}
return 0;
}
POJ2236 Wireless Network
http://poj.org/problem?id=2236
一个wifi网络图,给定n个点的坐标以及可以直接传播的最短距离d
接着是操作(访问):修理某些节点或询问两个是否能够连同
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
using namespace std;
#define MAXN 1001+5
double dis[MAXN][MAXN];
int fa[MAXN],rank[MAXN],n,m,x[MAXN],y[MAXN];
bool vis[MAXN];
int find(int a)
{
if(fa[a]==a)
return a;
else
return fa[a]=find(fa[a]);
}
void unite(int a,int b)
{
a=find(a);
b=find(b);
if(a==b)
return ;
if(rank[a]<rank[b])
fa[a]=b;
else
{
fa[b]=a;
if(rank[a]==rank[b])
rank[b]++;
}
return ;
}
bool same(int a,int b)
{
return find(a)==find(b);
}
void init()
{
for(int i=1;i<=n;i++)
{
rank[i]=0;
fa[i]=i;
vis[i]=false;
}
memset(dis,0x3f3f,sizeof(dis));
return ;
}
int main()
{
int a,b;
char c;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
if(i==j)
continue;
dis[i][j]=dis[j][i]=sqrt(pow((double)x[i]-x[j],2)+pow((double)y[i]-y[j],2));
}
dis[i][i]=0x3f3f;
}
while(cin>>c)
{
if(c=='S')
{
scanf("%d%d",&a,&b);
if(same(a,b))
printf("SUCCESS\n");
else
printf("FAIL\n");
}
else
{
scanf("%d",&a);
vis[a]=true;
for(b=1;b<=n;b++)
if(dis[a][b]<=m&&vis[b])
{
unite(a,b);
}
}
}
}
}
HDU1272 小希的迷宫
http://acm.hdu.edu.cn/showproblem.php?pid=1272
给定一个迷宫,依次读入边,判断是否合法(无环且连同)
连同等价于只有一个祖先
#include<cstdio>
#define MAXN 100000+5
int fa[MAXN],rank[MAXN];
bool flag,vis[MAXN];
int find(int a)
{
if(a==fa[a])
return a;
else
return fa[a]=find(fa[a]);
}
void unite(int a,int b)
{
a=find(a);
b=find(b);
if(a==b)
{
flag=true;
return ;
}
if(rank[a]<rank[b])
fa[a]=b;
else
{
fa[b]=a;
if(rank[a]==rank[b])
rank[a]++;
}
return ;
}
void init()
{
flag=false;
for(int i=1;i<=MAXN-5;i++)
{
rank[i]=0;
fa[i]=i;
vis[i]=false;
}
}
int main()
{
int m,n,a,b;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
if(n==-1&&m==-1)
break;
if(!n&&!m)
{
printf("Yes\n");
continue;
}
unite(n,m);
vis[n]=vis[m]=true;
while(1)
{
scanf("%d%d",&a,&b);
if(!a&&!b)
break;
unite(a,b);
vis[a]=vis[b]=true;
}
if(flag)
{
printf("No\n");
continue;
}
else
{
int k=0;
for(int i=1;i<=MAXN-5;i++)
if(vis[i]&&find(i)==i)
k++;
if(k>1)
printf("No\n");
else
printf("Yes\n");
}
}
return 0;
}
POJ1308 Is It A Tree?
http://poj.org/problem?id=1308
与上一题神似,只是把边变成有向
#include<cstdio>
#define MAXN 100000+5
int fa[MAXN];
bool vis[MAXN],mark[MAXN],flag;
int find(int a)
{
if(fa[a]==a)
return a;
else
return fa[a]=find(fa[a]);
}
void unite(int a,int b)
{
a=find(a);
b=find(b);
if(a==b)
{
flag=true;
return ;
}
fa[b]=a;
}
void init()
{
flag=false;
for(int i=1;i<=MAXN-5;i++)
{
fa[i]=i;
vis[i]=mark[i]=false;
}
}
int main()
{
int a,b,k=0;
while(1)
{
scanf("%d%d",&a,&b);
if(a==-1&&b==-1)
break;
if(!a&&!b)
{
printf("Case %d is a tree.\n",++k);
continue;
}
init();
unite(a,b);
vis[b]=true;
mark[a]=mark[b]=true;
while(1)
{
scanf("%d%d",&a,&b);
if(!a&&!b)
break;
if(vis[b])
flag=true;
unite(a,b);
vis[b]=true;
mark[a]=mark[b]=true;
}
if(flag)
{
printf("Case %d is not a tree.\n",++k);
continue;
}
else
{
int t=0;
for(int i=1;i<=MAXN-5;i++)
if(mark[i]&&find(i)==i)
t++;
if(t>1)
printf("Case %d is not a tree.\n",++k);
else
printf("Case %d is a tree.\n",++k);
}
}
return 0;
}