一篇搞懂深搜DFS

举报
璐画 发表于 2022/04/11 17:39:21 2022/04/11
【摘要】 核心代码:关于dfs参数问题,什么在变化,就把什么设置成参数。void dfs()//参数用来表示状态 { if(到达终点状态) { ...//根据题意添加 return; } if(越界或者是不合法状态) return; if(特殊状态)//剪枝 return ; ...

核心代码:

关于dfs参数问题,什么在变化,就把什么设置成参数。

void dfs()//参数用来表示状态  
{  
    if(到达终点状态)  
    {  
        ...//根据题意添加  
        return;  
    }  
    if(越界或者是不合法状态)  
        return;  
    if(特殊状态)//剪枝
        return ;
    for(扩展方式)  
    {  
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            标记;  
            dfs();  
            (还原标记);  
            //是否还原标记根据题意  
            //如果加上(还原标记)就是 回溯法  
        }  
 
    }  
} 

 先看模板,到这里伙计们肯定不理解到底什么含义,所以我在这里解释下,涉及到深搜的基本提,全是这个套路,现在不理解,先把框架记住,然后用框架去刷几道题就会发现新大陆了

现在,上一道深搜的考题

有一个大小为N×MN×M N\times MN×M的园子,雨后积起了水。八连通的积水被认为是连接在一起的。请求出园子里总共有多少水洼?八连通指的是下图中相对W的∗部分,‘W’表示积水,’ * '表示没有积水。

输入

10 12
W********WW*
*WWW*****WWW
****WW***WW*
*********WW*
*********W**
**W******W**
*W*W*****WW*
W*W*W*****W*
*W*W******W*
**W*******W*

输出

3

问题分析

首先定义一个二维数组存储这片下过雨的区域,然后双重for循环遍历一下,每次找到一个 ‘W’ 就记一次数,代表这里有一个水洼,如果继续遍历下去会找到与前面 ‘W’ 相连通的积水,而题上说了只要是相连通的积水就算是一个水洼,因此直接这样遍历是不行的。

为了解决这个重复计算的问题,可以定义一个作为递归的方法,将这个 ‘W’ 的坐标传入,并将这个积水去处,‘W’ 变为 ’ * ’ ,然后以这个坐标为中心,遍历它的八个方向,看看能不能找到下一个 ‘W’ ,找到后向下进行递归,将这个’W’传入本方法,继续进行去除,遍历,直到再也找不到相连通的积水,就表示这一处水洼全部清除了,完美解决重复计算的问题,也解决了两个相连通的积水相互找到对方,陷入无限递归的局面。

代码实现

import java.util.Scanner;
 
public class NumberOfPuddles {
	static int n, m;
	static char[][] field;
 
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		field = new char[n][];
		for (int i = 0; i < n; i++) {
			field[i] = sc.next().toCharArray();
		}
		int count = 0;	//计数器
		for (int i = 0; i < field.length; i++) {
			for (int j = 0; j < field[i].length; j++) {
				// 枚举整个n*m的园子,每找到一个'W'就代表找到了一个水洼
				// 然后用深搜的方式将连通的所有积水全部去除,防止重复计算
				if (field[i][j] == 'W') {
					count++;
					dfs(i, j);
				}
			}
		}
		System.out.println(count);
	}
 
	private static void dfs(int i, int j) {
		field[i][j] = '*';	//清除积水
		//遍历八个方向找到连通的积水
		for (int p = i - 1; p <= i + 1; p++) {
			for (int q = j - 1; q <= j + 1; q++) {
				if (p >= 0 && p < n && q >= 0 && q < m) {
					if (field[p][q] == 'W') {
						dfs(p, q);
					}
				}
 
			}
		}
	}
}

到这里,小伙伴们估计还是疑问很大,那么请仔细的对着框架,看这道题,看这个题的代码是不是和框架几乎一模一样啊。

深搜深层分析

题型分类:

写过这些入门题后,我们可以将DFS题分为两大类:


1 . 地图型:这种题型将地图输入,要求完成一定的任务。因为地图的存在。使得题意清楚形象化,容易理清搜索思路。

    AOJ 869-迷宫(遍历地图,四向搜索)
    HDU 1035-Robot Motion(指定方向搜索,迷路(循环)判断)HDU 1035-Robot Motion(指定方向搜索,迷路(循环)判断)
    HDU 1045-Fire Net(check函数,回溯)
 

2 . 数据型:这种题型没有给定地图,一般是一串数字或字母,要求按照一定的任务解题。相对于地图型,这种题型较为抽象,需要在数据中进行搜索。数据以数组的形式存储,那么只要将数组也当作一张图来进行搜索就可以了。

    HDU 1016-Prime Ring Problem(回溯、素数筛)
    HDU 1258-Sum It Up(双重DFS递归,去重技巧)
    HDU 1015-Safecraker(回溯,字符处理)
    HDU 2676-Sudoku(抽象,回溯)

(这里不列举了,全是一个大佬写的文章)
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。