【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.youkuaiyun.com/liujian20150808/article/details/50848646

本题参考:https://blog.youkuaiyun.com/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 结果

### Java 实现斐波那契数列的蓝桥杯题目及解答 #### 题目描述 给定正整数 \( n \),求斐波那契数列的第 \( n \) 项。 注意:由于结果可能会非常大,因此要求输出的结果是对 10007 取模后的值。 输入格式:单个整数 \( n \) (\( 1 \leq n \leq 1,000,000 \))。 输出格式:一个整数,表示斐波那契数列第 \( n \) 项对 10007 的取模结果。 --- #### 解决方案 以下是基于动态规划的思想来解决该问题的一种高效方法: ```java import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); int n = input.nextInt(); // 初始化数组大小为 n+2 是为了方便索引操作 int[] F = new int[n + 2]; F[1] = 1; F[2] = 1; if (n > 2) { for (int i = 3; i <= n; i++) { F[i] = (F[i - 1] + F[i - 2]) % 10007; } } System.out.println(F[n]); } } ``` 上述代码通过循环迭代的方式计算斐波那契数列中的每一项,并利用取模运算防止溢出[^1]。这种方法的时间复杂度为 \( O(n) \),空间复杂度也为 \( O(n) \)。 如果希望进一步优化空间复杂度,则可以仅保留最近的两项来进行状态转移: ```java import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); int n = input.nextInt(); if (n == 1 || n == 2) { System.out.println(1); return; } int prev1 = 1; // 表示 F(i-1) int prev2 = 1; // 表示 F(i-2) for (int i = 3; i <= n; i++) { int current = (prev1 + prev2) % 10007; prev2 = prev1; prev1 = current; } System.out.println(prev1); } } ``` 此版本的空间复杂度降低至 \( O(1) \)[^4],而时间复杂度仍保持为 \( O(n) \)。 --- #### 黄金分割比例的应用 对于较大的 \( n \),可以直接近似使用黄金分割比例 \( \phi = \frac{\sqrt{5} + 1}{2} \approx 1.6180339887 \) 来估算斐波那契数列的比例关系。然而,在实际编程比赛中通常不会采用这种方式,因为浮点误差可能导致精度不足[^2]。 --- #### 大规模数据处理注意事项 当 \( n \) 较小时,直接存储整个序列即可;但如果 \( n \) 很大(例如达到百万级别),则需特别关注内存占用以及性能瓶颈。此外,还需考虑中间结果是否会超出 `long` 数据类型的范围。在这种情况下,提前对每一步结果进行取模是一种常见且有效的策略[^5]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值