并查集入门水题练习

并查集入门水题练习:
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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值