合根植物(并查集)

问题描述
  w星球的一个种植园,被分成 m * n 个小格子(东西方向m行,南北方向n列)。每个格子里种了一株合根植物。

这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。

如果我们告诉你哪些小格子间出现了连根现象,你能说出这个园中一共有多少株合根植物吗?
  
输入格式
    第一行,两个整数m,n,用空格分开,表示格子的行数、列数(1<m,n<1000)。

接下来一行,一个整数k,表示下面还有k行数据(0<k<100000)

接下来k行,第行两个整数a,b,表示编号为a的小格子和编号为b的小格子合根了。

格子的编号一行一行,从上到下,从左到右编号。

比如:5 * 4 的小格子,编号:

1 2 3 4

5 6 7 8

9 10 11 12

13 14 15 16

17 18 19 20样例输入5 4

16

2 3

1 5

5 9

4 8

7 8

9 10

10 11

11 12

10 14

12 16

14 18

17 18

15 19

19 20

9 13

13 17样例输出5样例说明  其合根情况参考下图

在这里插入图片描述
这道题目考察的是并查集的用法,关于并查集大致算法,我在b站上看来一个讲解视频,讲的很清楚易懂,感谢!

这道题思路就是把每个单元格的根初始化为自己本身,然后,合并,最后遍历mn,找出根为本身的有几个,就分成几块。(因为其他连城一片的只有一个根)
最开始我想的是直接m
n-k-环数 后来发现这不止一个图,此法行不通,然后,参考网上思路及b站讲解才写出来,自己代码能力还很差,任重而道远,下面是主要实现代码:

#include<stdio.h>
//合根植物就是并查集的考察
//初始化parent[i]=-1 ;parent[i]=2,表示i与2 相连
void init(int parent[],int rank[],int n)
{
 int i;
 for(i=1;i<=n;i++)
 {
  parent[i]=i;
  rank[i]=0;
 }
} 
//向上找x的根
int find_root(int x,int parent[])
{
 int x_root=x;
 while(parent[x_root]!=x_root) 
   {
     x_root=parent[x_root];
    } 
  return x_root;
 } 
 
//把两个区域的值连起来
int union_root(int x,int y,int parent[],int rank[])
{
  int x_root=find_root(x,parent);
  int y_root=find_root(y,parent);
  if(x_root==y_root)  //两个拥有相同双亲,返回错误 
    {
       return 0;
    }
 else{
    if(rank[x_root]>rank[y_root])
      {
          parent[y_root]=x_root;   //y的双亲是x;  
      }    
    else if(rank[x_root]<rank[y_root]) 
      {
          parent[x_root]=y_root;
      }
    else{
          parent[x_root]=y_root;
          rank[y_root]++;
         } 
    return 1;
  }
} 
int main()
{
   int m,n;
   scanf("%d%d",&m,&n);
   int k;
   scanf("%d",&k);
   int count=0;
   int parent[m*n+2]={0};
   int rank[m*n+2]={0};
   init(parent,rank,m*n);
   long long str[100001][2]={0};    //每条边带两个顶点 
   for(int i=0;i<k;i++)
    {
      for(int j=0;j<2;j++)
      scanf("%d",&str[i][j]); 
    }
   for(int i=0;i<k;i++)
    {
       int x=str[i][0];  //x等于第i条边的第0个数字 
       int y=str[i][1];  //y等于第i条边的第1个数字 
       union_root(x,y,parent,rank);
     }
   for(int i=1;i<=m*n;i++)
     {
        if(parent[i]==i)
         {
            count++;
           continue;
          }
         else
            continue;
       }
   printf("%d",count);
   return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值