【Java】蓝桥杯PREV-54 合根植物

一、题目描述

二、代码

import java.util.Scanner;


public class Main {
	public static void main(String[] args) {
		@SuppressWarnings("resource")
		Scanner in = new Scanner(System.in);
		int m = in.nextInt();
		int n = in.nextInt();
		int k = in.nextInt();
		int repeat_num = 0;
		int res = 0;
		int all = m * n ;
		int[] book = new int[all + 1];
		
		
		for(int i = 0; i < k; i++){
			int a = in.nextInt();
			int b = in.nextInt();
			
			if(book[a] == 0 && book[b] == 0){
				book[a] = book[b] = ++res;
			}
			else if(book[a] != 0 && book[b] == 0){
				book[b] = book[a];
			}
			else if (book[b] != 0 && book[a] == 0) {
				book[a] = book[b];
			}
			else if (book[a] != 0 && book[b] != 0 && book[a] != book[b]) {
				int tmp = book[b];
				
				for(int j = 1; j <= all; j++){
					if(book[j] == tmp){
						book[j] = book[a];
					}
				}
				repeat_num ++;
			}
		}
		res = res - repeat_num;
		for(int i = 1; i <= m * n; i++){
			if(book[i] == 0)
				res++;
		}
		
		System.out.println(res);
		
	}

}

三、思路记录

  1. 读入不谈。解题思路来源于 Floodfill 。
  2. 使用一个数组(此处是book[ ])记录 种植园格子里的植物是否连根。
  3. 个人觉得这道题表述不合理,最终计算的并非是“合根植物的数量”,而是“植物的数量”。导致解题最终需要再遍历一遍数组,找出“没有连根情况发生的植物”。
  4. 每次读入两株植物(设为a、b):
  • 1)如果都没有,即把它们都标记为连根植物,book[a] = book[b];
  • 2)如果一株植物已经被标记过(假设为a)、一株植物未被标记过(假设为b),那么 book[b] = book[a];
  • 3)如果两株植物都被标记过,注意会有两种情况:3.1)这两株植物已经在 book 数组中被标记为同一株连根植物,那么不处理即可 ;3.2)这两株植物在目前的 book 数组中是不同株连根植物,现要把它们标记为同一株连根植物,那么就需要将其中的一株植物标记为另一株植物,之后在记录植物数量的变量中(此处为res)减去 1,即原来我们以为是两株植物、结果现在才发现是同一株、那么总数要减一。
  • 4)此处给出样例输入输出运算结束的 book 数组。
book数组标记相应格子的植物是否发生连根,以及连根情况。
相同数字意味着是同一株合根植物

 

四、结果

日常不会改进算法...下载了数据,运算结果是正确的。

五、改进

博主已被自己蠢死...

并查集并查集并查集....

参考资料:

并查集简略易懂介绍:https://blog.csdn.net/liujian20150808/article/details/50848646

本题参考:https://blog.csdn.net/qq_34525938/article/details/79334313

5.1 代码

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;



public class Main {
	static int[] book;
	public static void main(String[] args) {
		@SuppressWarnings("resource")
		Scanner in = new Scanner(System.in);
		int m = in.nextInt();
		int n = in.nextInt();
		int k = in.nextInt();
		
		int all = m * n ;
		book = new int[all];
		
		for(int i = 0; i < all; i++){
			book[i] = i;
		}
		
		int a, b;
		for(int i = 0; i < k; i++){
			a = in.nextInt() - 1;
			b = in.nextInt() - 1;
			union(a, b);
		}
		
		Set<Integer> set = new HashSet<Integer>();
		for(int i = 0; i < all; i++){
			set.add(find(i));
		}
		
		System.out.println(set.size());
	}
	
	private static void union(int a, int b) {
		int find_res_a, find_res_b;
		find_res_a = find(a);
		find_res_b = find(b);
		
		//随意指定一项作为源头
		if(find_res_a != find_res_b)
			book[find_res_a] = find_res_b;
	}
	
	
	private static int find(int x) {
		//寻找 x 的源头
		int r = x;
		while(book[r] != r)
			r = book[r];
		return r;
	}

}

5.2 结果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值