DFS/BFS--(深度优先搜索/广度优先搜索)入门讲解

DFS
首先先看下面这个有关迷宫的问题引入思考。

密室逃脱

Description
每天刷题太枯燥了,为了放松一下自己,你,zjx和hhy约好了周末一起去玩密室逃脱。一般的密室逃脱对你们没有什么吸引力了,所以你们找到了一个更好玩的密室逃脱。
我们可以把整个密室看成一个 n * m 的网格图(包含很多房间),其中每个房间都是一个1 * 1的单元格, 有一些房间有机关,进入后会失去游戏资格。我们将没有机关的房间用0表示,有机关的房间用1表示。
迷宫的规则是开局的时候zjx和hhy被随机放到一个房间里(保证被放房间是没有机关的),单位时间内他们可以选择进入到相邻的房间(上下左右),也可以选择不动。两人相遇即可通过游戏,越短时间通过游戏获得的奖品越好,所以你们要在最短的时间通过游戏,触碰机关失去游戏资格不会获得奖品。你在密室外指挥他们从自己的起点出发使他们相遇(你可以看到迷宫的地图并且你们之间可以联系),现在请你计算出他们两个从出发点到相遇需要的最短时间。

Input
第一行两个整数n, m表示网格图的大小。

第二行四个整数x1, y1, x2, y2分别表示zjx和hhy的起点横纵坐标。

接下来一个矩阵:n行,每行m个数(只含0和1),表示地图。

1 <= n, m <= 100, 1 <= x1, x2 <= n, 1 <= y1, y2 <= m

Output
一行,一个整数,表示zjx和hhy相遇的最短时间。

思路:

一看题目很多的字,但是其实你耐心读下去,提取信息会发现很简单,就是两个憨憨一起走一个迷宫,俩人都有自己的初始位置,他们同时走,每走一步都消耗一样的单位时间。然后问他们俩相遇的最短时间。
我们简化问题,两个人同时走让你不好思考,那你就把问题转化为一个人不动,然后另一个人来找这个人的最短路max_sum径是多少(因为走单位格移动的时间是单位时间,换成求路径更方便你思考),之后这个max_sum再除以2就是他们俩同时走的时间了。(当然,你思考一下,直接除以2是完全正确的吗?)
当然不是的了,因为两个人之间的最优路线的路径是奇数的话,那么势必有一个人要多走一步,判断一下加一即可,是偶数的时候便直接除以2.
下面开始讲核心算法DFS/BFS.

BFS
相当于一个队列,队列没学好的可以看下队列的基本知识便可以更好理解BFS的运用。
首先是存图,可以用最简单的二维表(二维数组)的方式存一个图。循环嵌套存入地图,应该不用过多讲解了。之后是定义一个队列,这个队列你可以自己手动写一个,也可以直接用STL里的queue队列。接着是一个循环,每次都要处理队列头的位置,寻找出这个位置能走到的所有位置,把更新出来的位置入队。之后删掉表头。这样就可以实现“千军万马”地毯式搜索的效果了。

例如此时队列头的位置在start(2,1),

1start
1
1
end

那么你下一步可以走的位置可以是(1,2),(2,3),(3,2),(2,1)有障碍物不能走。

here
1starthere
here
1
1
end

你可能会疑惑如何让他判断所有下一步能走的点,你需要定义一个位置数组,这里我习惯定义一个nest数组,nest[4][2]={ {0,1},{1.0},{0,-1},{-1,0} },也就是说循环一下就会每次依次默认向右,下,左,上,进行试探搜索。比方说startx=2,starty=1,那么下一步向右t,x=2+0=2,ty=1+1=2,(2,2)没有障碍物,可以走,把这个位置入队,你可以思考一下整个搜索的过程,如果地图没问题,最先搜索到的目的位置的那条线也就是最短距离,也就是你要找的答案。

(DFS和BFS的具体实践等有空再更,你可以试着直接写一下DFS/BFS试一试)

代码如下:

#include <iostream>
#include <stdio.h>
using namespace std;
int n,m,map[401][401]={0},book[401][401]={0};
struct node{
    int x;
    int y;
    int step;
};
int nest[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
node queue[160001];
int main()
{
    int i,j,head,tail,a,b,tx,ty,x1,y1,x2,y2;
    cin>>n>>m>>x1>>y1>>x2>>y2;
    for(i=1;i<=n;i++)
    {
    	for(j=1;j<=m;j++)
    	{
    		cin>>map[i][j];
		}
	}
    head=1;
    tail=1;
    queue[tail].x=x1;
    queue[tail].y=y1;
    queue[tail].step=0;
    book[x1][y1]=1;
    tail++;
    while(head!=tail)
    {
        for(i=0;i<4;i++)
        {
            tx=queue[head].x+nest[i][0];
            ty=queue[head].y+nest[i][1];
            if(tx>n||ty>m||tx<1||ty<1)
            {
                continue;
            }
            if(book[tx][ty]==0&&map[tx][ty]==0)
            {
                queue[tail].x=tx;
                queue[tail].y=ty;
                queue[tail].step=queue[head].step+1;
                book[tx][ty]=1;
                if(tx==x2&&ty==y2)
        		{
        			if(queue[tail].step%2==0)
        			{
        				cout<<queue[tail].step/2<<endl;
        				break;
					}
					else
        			cout<<queue[tail].step/2+1<<endl;
        			break;
				}
                tail++;
            }
        }
        head++;
    }
    cout<<endl;
    return 0;
    }
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值