问题描述
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,找出根为本身的有几个,就分成几块。(因为其他连城一片的只有一个根)
最开始我想的是直接mn-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;
}