DFS BFS

深搜和广搜 (DFS & BFS)

这里介绍深度搜索和广度搜索的基本知识,适合学习搜索算法的初学者,如果是高手请手下留情!

一、总体介绍

搜索算法是利用计算机的高性能来有目的的穷举一个问题的部分或所有的可能情况,从而求出问题的解的一种方法。搜索过程实际上是根据初始条件和扩展规则构造一棵解答树并寻找符合目标状态的节点的过程。通俗点说,搜索说枚举所有可能答案,然后找出最佳答案的一个方法。

下面的说的深度搜索和广度搜索,都是枚举可能答案,但是遍历的顺序不一样,所以在运用在不同的地方。

二、深度优先搜索(DFS)(Depth-First Search)

正如名字上的不同那样,深度优先搜索就是尽可能的“深”的图。

如右图所示,深度搜索的顺序应当是:

a->b->d(没有路了,回溯到a)->c->e->g(没有路了,回溯到e)->h(没有路了,回溯到c)->f(本次搜索结束)

好了,了解什么是DFS后我们来看看如何描述这个算法:

例题1:HDU1010Tempter of the Bone 题目大意讲的是有一只小狗被困在迷宫里面了,迷宫用S(起点)、D(出口)、X(墙)、.(过道)组成,小狗每秒移动一格,出去的条件的在正好T秒时走到D处,而且每个点上只能呆一秒,不能走已经走过的路。

代码:

# include 
# include 
# include 
using namespace std;
char map[9][9];
int n,m,t,di,dj;
bool escape;
int dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}}; 

void dfs(int si,int sj,int cnt)
{    int i,temp;
   if(si>n||sj>m||si< =0||sj<=0) return;
   if(cnt==t&&si==di&&sj==dj)    escape=1;
   if(escape) return; 

   temp=(t-cnt)-abs(si-di)-abs(sj-dj);
   if(temp<0||temp&1) return;
   for(i=0;i<4;i++){
      if(map[si+dir[i][0]][sj+dir[i][1]]!='X')
	  {
         map[si+dir[i][0]][sj+dir[i][1]]='X';
         dfs(si+dir[i][0],sj+dir[i][1],cnt+1);
         map[si+dir[i][0]][sj+dir[i][1]]='.';
      }
   }
   return;
} 

int main()
{
	int i,j,si,sj;
	while(cin>>n>>m>>t)
	{
	  if(n==0&&m==0&&t==0) break;
	  int wall=0;
	  for(i=1;i< =n;i++)
         for(j=1;j<=m;j++)
		 {
            cin>>map[i][j];
            if(map[i][j]=='S') { si=i; sj=j; }
            else if(map[i][j]=='D') { di=i; dj=j; }
            else if(map[i][j]=='X') wall++;
         }
       if(n*m-wall< =t)
	   {
		   cout<<"NO"<<endl; continue;="" }="" escape="0;" map[si][sj]="X" ;="" dfs(si,sj,0);="" if(escape)="" cout<<"yes"<<endl;="" else="" cout<<"no"<<endl;="" return="" 0;="" <="" pre="">

三、广度优先搜索(BFS)(Breadth-First Search)

广度优先搜索其实也很简单,只不过遍历的顺序不同罢了,也是上面那副图,广度优先搜索顺序是:

a->b->c (这层没有节点了,拓展到下层) -> d -> e -> f (这层没有节点了,拓展到下层) -> g - >h

从这个顺序上就很容易看出DFS和BFS的区别。不过虽然看似小小的不同,其效果可是大大的不同的,BFS一般又在寻找“最”什么的问题上。废话少说,还是先来一个例题。

例题2:HDU1253胜利大逃亡 题目中文的,有图片,所以这里就不描述。

这个题目如果用DFS也可是得出答案,但是如果用DFS做要搜索完全部的路,才能找到最短的时间,而BFS是一层一层展开的,所以只要碰到出口,那必定是用时最少的一条。节约了很多时间,讲到这里,大家是否对搜索有了初步的了解了?

代码(队列实现):

#include
#include
using namespace std;
#include
int di[6][3]={{0,0,1},{0,1,0},{1,0,0},{0,0,-1},{0,-1,0},{-1,0,0}};
int map[101][101][101];
int A,B,C,T;
struct node
{
	int x;
	int y;
	int z;
	int t;
	node(int x,int y,int z,int t)
	{
		this->x=x;
		this->y=y;
		this->z=z;
		this->t=t;
	}
};
void bfs()
{
	queue q;
	q.push(node(0,0,0,0));
	map[0][0][0]=1;
	while(!q.empty())
	{
		node now=q.front();
		q.pop();
		int tx,ty,tz;
		for(int i=0;i<6;i++)
		{
			tx=now.x+di[i][0];
			ty=now.y+di[i][1];
			tz=now.z+di[i][2];
			if(tx>=0&&tx=0&&ty=0&&tz<c &&map[tx][ty][tz]!="1)" {="" if(tx="=A-1&&ty==B-1&&tz==C-1&&now.t+1<=T)" printf("%d\n",now.t+1);="" return;="" }="" q.push(node(tx,ty,tz,now.t+1));="" map[tx][ty][tz]="1;" printf("-1\n");="" int="" main()="" t;="" scanf("%d",&t);="" while(t--)="" scanf("%d%d%d%d",&a,&b,&c,&t);="" for(int="" i="0;i<A;i++)" j="0;j<B;j++)" k="0;k<C;k++)" scanf("%d",&map[i][j][k]);="" bfs();="" return="" 0;="" <="" pre="">


以下是对DFSBFS和UCS的介绍: DFS(深度优先搜索):总是扩展最深层的节点,使用的是LIFO队列,即使用的是stack栈。DFS在生成节点时做的goal test,因此在搜索树中,DFS总是沿着最深的路径搜索,直到找到目标状态或者无法继续搜索为止。DFS的优点是空间复杂度低,但是可能会陷入局部最优解。 BFS(广度优先搜索):总是扩展最浅层的节点,使用的是FIFO队列,即使用的是queue队列。BFS在扩展节点时做的goal test,因此在搜索树中,BFS总是沿着最浅的路径搜索,直到找到目标状态或者无法继续搜索为止。BFS的优点是可以找到最优解,但是空间复杂度较高。 UCS(最佳优先搜索):总是扩展当前代价最小的节点,使用的是priority queue优先队列。UCS在扩展节点时做的goal test,因此在搜索树中,UCS总是沿着代价最小的路径搜索,直到找到目标状态或者无法继续搜索为止。UCS的优点是可以找到最优解,且可以在frontier集中记录所有合适的解,但是空间复杂度较高。 以下是对DFSBFS和UCS的演示: 假设我们要在一个迷宫中找到从起点到终点的最短路径,其中1表示墙,0表示可以通过的路。迷宫如下所示: ``` 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 1 1 0 1 1 0 1 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 1 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 ``` 我们可以使用DFSBFS和UCS来寻找最短路径。其中DFS使用stack栈,BFS使用queue队列,UCS使用priority queue优先队列。具体实现可以参考以下代码: ```python # DFS def dfs(maze, start, end): stack = [(start, [start])] visited = set() while stack: node, path = stack.pop() if node == end: return path if node not in visited: visited.add(node) for neighbor in get_neighbors(maze, node): stack.append((neighbor, path + [neighbor])) return None # BFS def bfs(maze, start, end): queue = [(start, [start])] visited = set() while queue: node, path = queue.pop(0) if node == end: return path if node not in visited: visited.add(node) for neighbor in get_neighbors(maze, node): queue.append((neighbor, path + [neighbor])) return None # UCS def ucs(maze, start, end): queue = [(0, start, [start])] visited = set() while queue: cost, node, path = heapq.heappop(queue) if node == end: return path if node not in visited: visited.add(node) for neighbor in get_neighbors(maze, node): new_cost = cost + 1 heapq.heappush(queue, (new_cost, neighbor, path + [neighbor])) return None # 获取邻居节点 def get_neighbors(maze, node): neighbors = [] row, col = node if row > 0 and maze[row-1][col] == 0: neighbors.append((row-1, col)) if row < len(maze)-1 and maze[row+1][col] == 0: neighbors.append((row+1, col)) if col > 0 and maze[row][col-1] == 0: neighbors.append((row, col-1)) if col < len(maze[0])-1 and maze[row][col+1] == 0: neighbors.append((row, col+1)) return neighbors ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值