搜索算法详解(DFS/BFS)

好多人喜欢把搜索算法和动态规划,图论并列来看,似乎搜索算法是一个很独立的算法。(我以前就是这么想的,以至于好长一段时间没有掌握搜索的核心。)实际上,搜索算法是隶属于图论算法的,他的作用是把整个图遍历一遍(就是把整个图不重不漏地扫一遍)当你做过许多搜索的题你就会发现,这些题都是一样的,都是把整个图遍历一遍就完,没有任何技巧可言。
在这里插入图片描述
根据扫描的顺序不同,就有了深度优先搜索和广度优先搜索。如果是一个一维的数据结构,比如说数组,那么扫一遍很简单,用for循环从第一个数扫到最后一个数就ok了。但是图这种数据结构就比较难遍历,怎样不重不漏地遍历完所有的点呢?

深度优先搜索

广度优先搜索

搜索的两类题型

一种就是很直白的,要你把整个图遍历一遍,另一种是比较隐形的,你甚至都不知道这个题跟图论有什么关系。先看两个题再说

第一题:迷宫

一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由 n∗n 的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行。

同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到点B,问在不走出迷宫的情况下能不能办到。

如果起点或者终点有一个不能通行(为#),则看成无法办到。

注意:A、B不一定是两个不同的点。

输入格式

第1行是测试数据的组数 k,后面跟着 k 组输入。

每组测试数据的第1行是一个正整数 n,表示迷宫的规模是 n∗n 的。

接下来是一个 n∗n 的矩阵,矩阵中的元素为.或者#。

再接下来一行是 4 个整数 ha,la,hb,lb,描述 A 处在第 ha 行, 第 la 列,B 处在第 hb 行, 第 lb 列。

注意到 ha,la,hb,lb 全部是从 0 开始计数的。

输出格式

k行,每行输出对应一个输入。

能办到则输出“YES”,否则输出“NO”。

数据范围

1≤n≤100

输入样例:

2
3
.##
…#
#…
0 0 2 2
5

###.#
…#…
###…
…#.
0 0 4 0

输出样例:

YES
NO

第二题 小猫爬山

翰翰和达达饲养了N只小猫,这天,小猫们要去爬山。

经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。

翰翰和达达只好花钱让它们坐索道下山。

索道上的缆车最大承重量为W,而N只小猫的重量分别是C1、C2……CN。

当然,每辆缆车上的小猫的重量之和不能超过W。

每租用一辆缆车,翰翰和达达就要付1美元,所以他们想知道,最少需要付多少美元才能把这N只小猫都运送下山?

输入格式

第1行:包含两个用空格隔开的整数,N和W。

第2…N+1行:每行一个整数,其中第i+1行的整数表示第i只小猫的重量Ci。

输出格式

输出一个整数,表示最少需要多少美元,也就是最少需要多少辆缆车。

数据范围

1≤N≤18,
1≤Ci≤W≤108

输入样例:

5 1996
1
2
1994
12
29

输出样例:

2
这两道题都很经典,第一题直接把图告诉给你,为了更加直白一点,我把题目中样例中的图再画一遍
在这里插入图片描述

这就是第一题的图,粉色可以通行,蓝色不能通行,我们要从A点走到B点,问你能不能走到。我们一眼就能看出来能走到,那么电脑怎么能知道能不能走到呢,一个方法就是从A点开始走,把A点能走到的地方都走一遍,如果途中走到了B,就能到达,如果所有地方里边没有B,就走不到。而这个过程就是对整个图的一个遍历。
大家先仔细想想其中的道理,看是不是把整个图遍历一遍就能得到答案,在这里我们要注意一下,不一定是遍历整个图,而是遍历A所能到达的这个图。如果当然这个题只问了能不能到达B,所以当我们遍历到B的时候可以直接得出答案Yes。

AC代码
#include<bits/stdc++.h>  //万能头文件
using namespace std;
const int maxn=110;

int k,n;
char ch[maxn][maxn];//存储地图
bool vis[maxn][maxn];//存储每个点是否被遍历过,如果遍历过就不再遍历他
int ax,ay,bx,by;//起点和终点
int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};//用来寻找下一个点坐标的方向数组
int ans;

void dfs(int ax,int ay){
	vis[ax][ay]=true;//表示该点已经被遍历过
	if(ax==bx&&ay==by){//如果遍历到终点,ans就置为1,返回。
		ans=1;
		return;
	}
		
	for(int i=0;i<4;i++){
		int nx=ax+dx[i],ny=ay+dy[i];
		if(nx<0||ny<0||nx>=n||ny>=n)	continue;
		if(ch[nx][ny]=='#')	continue;
		if(vis[nx][ny])	continue;	

		if(dfs(nx,ny))	return true;
	}
	return false;
}

int main(){
	scanf("%d",&k);
	while(k--){
		scanf("%d",&n);
		for(int i=0;i<n;i++)
			scanf("%s",ch[i]);
		ans=0;
		memset(vis,0,sizeof vis);//每次要把数组初始化成0
		scanf("%d %d %d %d",&ax,&ay,&bx,&by);
		
		if(ch[ax][ay]=='#'||ch[bx][by]=='#'){
			printf("NO\n");
			continue;
		}//起点或终点如果是‘#’的话,答案直接为0
		
		dfs(ax,ay); //不是说遍历(ax,ay),而是从(ax,ay)开始遍历。
		
		if(ans)	printf("YES\n");
		else printf("NO\n");
	}
	return 0; 
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值