DFS求解水洼数目(java版)

题目描述

有一个大小为 N * M 的园子,雨后积起了水。八连通的积水被认为是连接在一起的。请求出
园子里总共有多少水洼?(八连通指的是下图中相对 W 的*的部分)

***
*W*
***

限制条件

N, M ≤ 100

样例:

输入
N=10, M=12

园子如下图('W’表示积水, '.'表示没有积水)

在这里插入图片描述

输出

3

思路分析

这道题目很经典,值得以后多去研究研究。问题是要我们求解出连着的一片的水洼的数量,对于这类经典的问题,使用其它迭代等的方法是难以求解的,因为我们不知道连着的积水的区域有多少,对于这类问题的求解,我们是采用常用的无死角搜索的深度优先搜索dfs算法来解决,因为dfs能够帮助我们搜索出所有的可能,尝试去走每一条路线,直到所有的路线都被走完了,那么dfs就终止了。

其中涉及到搜索以自己为中心的八个方向的搜索,所以存在着八个平行状态的搜索,这里使用到了一个技巧就是使用两层的for循环来进行处理。

这里还有一个技巧就是当发现这个位置有积水的时候就把这个位置变为干燥,这样在往下搜索的过程中就能避免往上搜索而造成递归无法出去的问题。这样当一个dfs搜索完之后那么它周围的积水都被清除掉了,那么继续寻找下一个有积水的地方然后进行dfs,当所有的积水区域都被干燥之后那么水洼的数量就计算出来了。

代码实现

package LanQiao;

import java.util.Scanner;

/*
 * 有一个大小为 N*M 的园子,雨后积起了水。八连通的积水被认为是连接在一起的。请求出 园子里总共有多少水洼?(八连通指的是下图中相对 W 的*的部分)
 *** W* 限制条件 N, M ≤ 100 样例: 输入 N=10, M=12 园子如下图('W'表示积水, '.'表示没有积水) W........WW.
 * .WWW.....WWW ....WW...WW. .........WW. .........W.. ..W......W.. .W.W.....WW.
 * W.W.W.....W. .W.W......W. ..W.......W. 输出 3
 */
public class ShuiWa_num
{
	private static int n;
	private static int m;

	public static void main(String[] args)
	{
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		char[][] a = new char[n][];
		for (int i = 0; i < n; i++)
		{
			a[i] = sc.next().toCharArray();
		}
		int cnt = 0;
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < m; j++)
			{
				if (a[i][j] == 'W')
				{
					dfs(a, i, j);//清除一个水洼
					cnt++;
				}
			}
		}
		System.out.println(cnt);
	}

	private static void dfs(char[][] a, int i, int j)
	{
		a[i][j] = '.';
		//上下左右的模板
		//搜索八个平行状态然后看一下连通的水洼
		//因为涉及到八个平行状态那么可以使用for循环,但是我们可以使用嵌套两个for循环的技巧来进行处理
		//因为加的都是-1 0 1 而1而且左上角到右下角
		//行的长度: arr.length 列的长度: arr[0].length
		for (int k = -1; k < 2; k++)
		{//-1,0,1
			for (int l = -1; l < 2; l++)
			{//-1,0,1
				if (k == 0 && l == 0)
					continue;

				if (i + k >= 0 && i + k <= n - 1 && j + l >= 0//确定边界
						&& j + l <= m - 1)
				{
					if (a[i + k][j + l] == 'W')
						dfs(a, i + k, j + l);
				}
			}
		}
	}
}

运行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sparky*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值