蓝桥杯 2018-9 全球变暖

本文探讨了如何使用编程解决实际问题,通过算法求解一张海域照片中因全球变暖可能被海水淹没的岛屿数量。博主分享了两种尝试的解决方案,包括深度优先搜索(DFS)和联通块分析,并解释了代码中出现的错误和优化思路。
摘要由CSDN通过智能技术生成

你有一张某海域NxN像素的照片,".“表示海洋、”#"表示陆地,如下所示:


.##…
.##…
…##.
…####.
…###.

其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

例如上图中的海域未来会变成如下样子:





…#…

请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。

输入
第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。

照片保证第1行、第1列、第N行、第N列的像素都是海洋。

输出
一个整数表示答案。
样例输入
7

.##…
.##…
…##.
…####.
…###.

样例输出
1

强调一件让自己从小到大都因为这件事懊悔的事情:读题!!!!!读题!!!!!!读题!!!!!
第一眼,以为让我求淹没后的地图长啥样,第二眼以为让我求还剩几个#,最后最后,当我看了题解才知道是求淹没了几个岛屿!!!!!!!救命!!!!!!!

无论哪个我都是第一眼有思路的。求淹没了几个岛屿,求呗,遍历地图,只要是四周又水,也就是被淹没的(或者说不是#,因为被淹没变成了水的)我就用book数组标记为0,遍历完地图后,我再遍历book数组,只要是1就表示改点还是岛屿,计数器+1,然后dfs,找与其联通的,把与它相连的都变为0.最后输出计数器个数。
这个思路也没啥大问题呀。

import java.util.Scanner;

public class t91 {
	static char[][] map;
	static int[][] book;

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();
		scanner.nextLine();
		map = new char[n][n];
		book = new int[n][n];
		for (int i = 0; i < n; i++) {
			String temp = scanner.nextLine();
			char[] temp0 = temp.toCharArray();

			for (int j = 0; j < n; j++) {
				map[i][j] = temp0[j];
				// book[i][j] = 1;
			}
		}

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if (map[i][j] == '#') {
					book[i][j] = 1;
					if (check(i, j)) {
						book[i][j] = 0;
					}
				}
			}
		}
		int sum = 0;
//		for (int i = 0; i < book.length; i++) {
//			for (int j = 0; j < book.length; j++) {
//				if (book[i][j] == 1) {
//					sum++;
//				}
//			}
//		}
//		System.out.println(sum);
		for (int i = 0; i < book.length; i++) {
			for (int j = 0; j < book.length; j++) {
				if (book[i][j] == 1) {
					sum++;
					dfs(i, j);
				}
			}
		}
		System.out.println(sum);

	}

	private static void dfs(int i, int j) {
		// TODO Auto-generated method stub
		int[][] dire = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
		for (int k = 0; k < 4; k++) {
			int x = i + dire[k][0];
			int y = j + dire[k][1];
			if (book[x][y] == 1) {
				book[x][y] = 0;
				dfs(x, y);
			}
		}
	}

	private static boolean check(int i, int j) {
		// TODO Auto-generated method stub
		int[][] dire = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
		for (int k = 0; k < 4; k++) {
			int x = i + dire[k][0];
			int y = j + dire[k][1];
			if (map[x][y] == '.') {
				return true;
			}
		}
		return false;
	}
}

但是提交显示运行错误。
另一种解法:
dfs,其实涉及到求联通块
遍历地图,每次找到一个#,我们就dfs进入,深入寻找,也就是找连通块,在这个过程中我们同时判断是否有一个#,四周都没有海水,也就是不会淹没,那么我们可以记录,如果存在说明他不会淹没,如果不存在说明他会淹没,计数器+1,不要忘了把走过的设置为已走。
上面是思路,具体实现细节有好多方法,我看到一个是设置了ans数组,ans[i]表示第i个连通块不会被淹没的#的个数,遍历完地图后,再遍历ans,只要ans值为0,就有一个岛屿被完全淹没了,计数器加1.

import java.util.Scanner;

public class jt9 {
	static char[][] map;
	static int[][] book;
	static int[] ans;
	static int num = 0;
	static int n = 0;

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		n = scanner.nextInt();
		scanner.nextLine();
		map = new char[n][n];
		book = new int[n][n];
		ans = new int[n * n];
		for (int i = 0; i < n; i++) {
			String temp = scanner.nextLine();
			char[] temp0 = temp.toCharArray();
			// ans[i] = -1;
			for (int j = 0; j < n; j++) {
				map[i][j] = temp0[j];
				// book[i][j] = 1;
			}
		}

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if (map[i][j] == '#' && book[i][j] == 0) {
					dfs(i, j);
					num++;
				}
			}
		}
		int sum = 0;
		for (int i = 0; i < num; i++) {
			if (ans[i] == 0) {
				sum++;
			}
		}
		System.out.println(sum);

	}

	private static void dfs(int i, int j) {
		book[i][j] = 1;
		int[][] dire = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
		int flag = 0;
		for (int k = 0; k < 4; k++) {
			int x = i + dire[k][0];
			int y = j + dire[k][1];
			if (x >= 0 && y >= 0 && x < n && y < n && map[x][y] == '.') {
				flag = 1;
			}
		}
		if (flag == 0)
			ans[num]++;
		for (int k = 0; k < 4; k++) {
			int x = i + dire[k][0];
			int y = j + dire[k][1];
			if (x >= 0 && y >= 0 && x < n && y < n && map[x][y] == '#' && book[x][y] == 0) {
				dfs(x, y);
			}
		}
	}
}

上面代码仅供参考,没有通过,显示运行错误,求指教,实在挑不出来了!!!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值