污染水域_200分_A/B复用卷_BFS/层序遍历/图

污染水域

题目描述:

  输入一行字符串,字符串可转换为 N*N 的数组,数组可认为是一个水域,
  判断多少天后,水域被全部污染。
  数组中只有0和1,0表示纯净,1表示污染,
  每天只可污染上下左右的水域,
  如果开始全部被污染,或永远无法污染,则返回-1。

输入输出描述:

输入描述:

  一行字符串

输出描述:

  多少天后,水域被全部污染

示例1:

输入:
	1,0,1,0,0,0,1,0,1
输出:
	2
解释:
	转化为数组为:
	1 0 1
	0 0 0
	1 0 1
	第一天后水域变为
	1 1 1
	1 0 1
	1 1 1
	第二天全部被污染
	1 1 1
	1 1 1
	1 1 1

示例2:

输入:
	0,0,0,0
输出:
	-1

解题思路:

典型的BFS求解题目,类似的思想可以从写二叉树/多叉树的层次遍历开始,如:102. 二叉树的层序遍历429. N 叉树的层序遍历
宽度优先的思想就是:逐一遍历这一层节点,并且将与这些节点直接相连的节点加入到待遍历的节点队列中,本层遍历完后,队列中剩下的待遍历节点就是第二层.....
如下图,5*5的矩阵,从中间开始污染:
在这里插入图片描述

代码:

public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	String[] split = scanner.nextLine().split(",");
	int n = (int) Math.sqrt(split.length);
	int[][] matrix = new int[n][n];
	// 记录下所有点是否都已经被污染了
	boolean[][] visited = new boolean[n][n];
	// 污染的时候计算上下左右点的坐标
	int[][] direction = new int[][] {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
	// 记录污染源
	Queue<int[]> pollution = new ArrayDeque<>();

	// 将字符串转换成 N * N 的矩阵
	for (int i = 0; i < split.length; i++) {
		int value = Integer.parseInt(split[i]);
		matrix[i / n][i % n] = value;
		// 记录下有哪些污染源
		if (value == 1) {
			pollution.offer(new int[] {i / n, i % n});
			visited[i / n][i % n] = true;
		}
	}

	// 如果没有污染源,则返回 -1
	if (pollution.isEmpty()) {
		System.out.println(-1);
		return;
	}

	// 每层污染源数量
	int levelSize = pollution.size();
	// 记录污染完所有点需要多少天
	int levels = 0;
	while (!pollution.isEmpty()) {
		// 从一层中弹出一个污染源,将这个污染源的上下左右还未被污染的点污染掉
		int[] poll = pollution.poll();
		levelSize--;

		// 开始污染:将这个污染源的上下左右还未被污染的点污染掉
		for (int[] item : direction) {
			int newX = item[0] + poll[0];
			int newY = item[1] + poll[1];

			// 没有越界、没有被污染,进行污染
			if (newX >= 0 && newX < n && newY >= 0 && newY < n && !visited[newX][newY]) {
				visited[newX][newY] = true;
				pollution.add(new int[]{newX, newY});
			}
		}

		// 一层污染源遍历结束,层数 + 1,重新初始化新的一层污染点数量
		// 即一层的污染源已经完成了它们的污染任务,紧接着让被它们这一层污染掉的点作为源头去污染其他的
		if (levelSize == 0) {
			levels++;
			levelSize = pollution.size();
		}
	}

	System.out.println(levels - 1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值