初级深度和广度优先搜索

深度和广度优先搜索都是基于图(数据类型)的操作。

如果搜索是以接近起始状态的程序依次扩展状态的,叫广(宽)度优先搜索。
如果扩展是首先扩展新产生的状态,则叫深度优先搜索广度 优先搜索: 广度优先搜索是按照树的层次进行的搜索,如果此层没有搜索完成的情况下不会进行下一层的搜索。

广度 优先搜索: 广度优先搜索是按照树的层次进行的搜索,如果此层没有搜索完成的情况下不会进行下一层的搜索。
深度优先搜索: 深度优先搜索是按照树的深度进行搜索的,所以又叫纵向搜索,在每一层只扩展一个节点,直到为树的规定深度或叶子节点为止。这个便称为深度优先搜索。

深度优先搜索

深度优先搜索用栈(stack)来实现,整个过程可以想象成一个倒立的树形:
把根节点压入栈中。
每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。并把这个元素记为它下一级元素的前驱。
找到所要找的元素时结束程序。
如果遍历整个树还没有找到,结束程序。

例如借助在对无向图进行深度遍历时去理解深搜:利用深度优先搜索实现深度优先遍历。深度优先遍历主要思想:首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点;当不存在未被访问过的顶点时,回到上个顶点,继续试探访问别的顶点,直至所有顶点都被访问过。
在这里插入图片描述
(圈内为顶点编号,外为遍历序号)

常常用深搜去解决最短路径问题:
例题如下:小哼和小哈在n*m(n,m<=50)规格的迷宫中走散了,迷宫中有障碍物(用1表示),有空格(用0表示),现要求小哼以最快速度找到小哈,输出最少步数。前提:小哼不能走到给定的迷宫外部,遇到障碍物不可通行。

#include<stdio.h>
int n,m,p,q,min=99999999;	 
int a[51][51],book[51][51];
void dfs(int x,int y,int step){
	int next[4][2]={{0,1},		//向右走 
					{1,0},		//向下走 
					{0,-1},		//向左走 
					{-1,0}};	//向上走 
	int tx,ty,k;
	//判是否到达小哈位置 
	if(x==p&&y==q){
		if(step<min)	min=step;	//更新最小值 
		return;						//达到之后直接结束不再进行下列代码 
	}
	//枚举四种走法 
	for(k=0;k<=3;k++){
		//计算下一个点的坐标 
		tx=x+next[k][0];
		ty=y+next[k][1];
		//判断是否还处在迷宫中 
		if(tx<1||tx>n||ty<1||ty>m)
		continue;
		//判断在路上还是遇到了障碍物 
		if(a[tx][ty]==0&&book[tx][ty]==0){
			book[tx][ty]=1;				//标记已经走过的路 
			dfs(tx,ty,step+1);			//尝试下一个点	 
			book[tx][ty]=0;				//尝试结束去除标记 
		}
	}
	return;
}
int main(void){
	int i,j,startx,starty;
	scanf("%d %d",&n,&m);
	//读入迷宫相关数据,即空格与障碍物的坐标 
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	//读入起始位置和终止位置 
	scanf("%d %d %d %d",&startx,&starty,&p,&q);
	//从第一个顶点开始搜索 
	book[startx][starty]=1;			//标记已经走过,防止重复经过 
	dfs(startx,starty,0);
	printf("%d",min);
	return 0;
} 

运行结果:

在这里插入图片描述

广(宽)度优先搜索

广度优先搜索使用队列(queue)来实现,整个过程也可以看做一个倒立的树形:
把根节点放到队列的末尾。
每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。
找到所要找的元素时结束程序。
如果遍历整个树还没有找到,结束程序。

例如借助在对无向图进行广度遍历时去理解广搜:利用广度优先搜索实现广度优先遍历。广度优先遍历主要思想:首先以一个未被访问过的顶点作为起始顶点,访问其所有的相邻的点,然后对每个相邻的顶点再访问它们所有的相邻未被访问过的点,直到所有点都被访问完,遍历结束。
在这里插入图片描述

针对上一题可以使用广度搜索去解决

#include<stdio.h> 
int a[51][51],book[51][51];
struct node{
	int x;
	int y;
	int s;
};
int main(void){
	struct node que[2510];
	int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
	int head=1,tail=1;
	int i,j,k,n,m,startx,starty,p,q,tx,ty,flag;
	scanf("%d %d",&n,&m);
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	scanf("%d %d %d %d",&startx,&starty,&p,&q);
	que[tail].x=startx;
	que[tail].y=starty;
	que[tail].s=0;
	tail+=1;
	book[startx][starty]=1;
	flag=0;					//用来标记是否达到目的地,1已到达,0未到达 
	while(head<tail){
		for(k=0;k<=3;k++){
			tx=que[head].x+next[k][0];
			ty=que[head].y+next[k][1];
			if(tx<1||tx>n||ty<1||ty>n)	continue;
			if(a[tx][ty]==0&&book[tx][ty]==0){
				book[tx][ty]=1;
				que[tail].x=tx;
				que[tail].y=ty;
				que[tail].s=que[head].s+1;
				tail+=1;
			}
			if(tx==p&&ty==q){
				flag=1;
				break;
			}
		}
		if(flag==1)
			break;
		head+=1;
	}
	printf("%d",que[tail-1].s);
	return 0;
}

搜索的要点:
(1)初始状态;
(2)重复产生新状态;
(3)检查新状态是否为目标,是结束,否转(2);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值