蓝桥杯 历届试题 合根植物(并查集)


问题描述

  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


样例说明

  其合根情况参考下图
在这里插入图片描述

解题思路:

  看到这题,我第一时间想到的是四连通图的解决方法,但是后来尝试了一下不行,因为这个数据量太大了,用深搜的话会超时的,而且将这些数据转换为图上的块也很麻烦。
  其实这题用并查集更容易解决,建立一个大小为n*m+1的数组(因为数据从1开始计算),将数组初始化为-1;用-1表示这个节点没有父节点,即这个节点作为一个集合的代表。
  当所有的节点合并完成后,遍历数组,统计-1的个数,即集合的个数(没有参数合根的点会单独作为一个集合)。-1的个数就是想要的结果。
  关于并查集的使用可以看这篇文章:并查集

解题代码:

import java.util.Arrays;
import java.util.Scanner;

public class 合根植物 {
	static int n;  //表示列
	static int m;  //表示行
	static int k;  //表示给出数据的行数
	static int[] arr; //用于并查集
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		m = scanner.nextInt();
		n = scanner.nextInt();
		k = scanner.nextInt();
		arr = new int[n*m+1];  //从1开始使用,0位不用
		Arrays.fill(arr, -1);   //用-1表示根节点,
		int a, b;
		for(int i=0; i<k; i++){
			a = scanner.nextInt();
			b = scanner.nextInt();
			if(union(a,b)){
				continue;
			}
		}
		int count = 0; //用于计算有多少种植物
		for(int i=1; i<arr.length; i++){
			if(arr[i]==-1){
				count++;
			}
		}
		System.out.println(count);
	}

	//将两个集合合并
	private static boolean union(int x, int y) {
		int xroot = findRoot(x);
		int yroot = findRoot(y);
		if(xroot==yroot){
			return true;
		}
		arr[xroot] = yroot;  //将x子树的根节点指向了y的根节点
		return false;
	}

	//查找x的根节点
	private static int findRoot(int x) {
		int t = x;
		while(arr[t] != -1){
			t = arr[t];
		}
		return t;
	}
}

测试结果:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/HC199854/article/details/106812878
今日推荐