【马的遍历变式】广搜与深搜

3 篇文章 0 订阅
3 篇文章 0 订阅

声明

作者非职业程序员,本文仅在分享自己的心得,错误较多欢迎指出,各位大佬不喜勿喷

本文采用和作者一样的小白一理解的的Pascal语言

这篇博客同时为了我的一位不懂代码但对算法十分感兴趣的朋友而写,故没有放一些“高级”元素

写得有些草率哈,请谅解:P

一、题目描述

国际象棋棋盘为8*8,现有一马🐎于盘角(1,1)出,求其遍历棋盘(不重复,不过起点)有几种走法(马🐎走日字)

二、题目分析

一道搜索题,通常我们从广(度优先)搜(索)和深(度优先)搜(索)两方面去考虑

1.什么是广搜bfs

广搜,就是广泛地搜索,遇到分叉时,把每一个岔路口都记录下来,再去挨个分析。这个记录形成一个队列,即先进先出,后进后出。好比过安检机,先放上去的行李先通过,后放上去的行李后通过。广搜(相对深搜)可以一定程度上节省时间复杂度。广搜记录了每一步能够搜索到的地方,先记录的搜完了再去搜下一个。

2.什么是深搜dfs

深搜,就是深入地搜索,基于递归,遇到分叉时,选一个路口继续前行,不撞南墙不回头,撞了南墙调个头。由于最先选的岔路在最后回溯到,后选的岔路最现在回溯时遇到,所以深搜构成了一个栈,即先进后出,后进先出。好比上房往烟囱里塞茅草,邻居发现了,拿着烧火棍叫你爬上去掏出来,于是最后塞进去的茅草最先被掏出,积压在最下的茅草要你最后爬进去掏。我刚开始学编程特喜欢用深搜(毕竟思维简单一些),结果不是超时就是超时,偶尔还会超时,顶多再超个时。

3.选什么

深搜并不能保证第一次就是最优解,要搜索所有可能的路径并不断回溯,标记一个点是否访问过然后再回溯中清除标记,故一个点可能被串好几次门。而广搜记录点由近及远,每个分叉点总是以最短路径被访问。一个结点假如第二次被访问,第二次的路径肯定不会比第一次的短,是以就没有需要再从这个结点向周围深入搜索――第一次这个结点已经被访问过了,第二次只会获得更差的解。同一个点最多只可能被访问一次。每访问一个结点,它的邻居也要被搜查一次。而最坏情况下,所有点都被搜索一次,时间复杂度为O(E)。

BFS与DFS的讨论:BFS:这是一种基于队列这种数据结构的搜索方式,它的特点是由每一个状态可以扩展出许多状态,然后再以此扩展,直到找到目标状态或者队列中头尾指针相遇,即队列中所有状态都已处理完毕。
DFS:基于递归的搜索方式,它的特点是由一个状态拓展一个状态,然后不停拓展,直到找到目标或者无法继续拓展结束一个状态的递归。

优缺点:BFS:对于解决最短或最少问题特别有效,而且寻找深度小,但缺点是内存耗费量大(需要开大量的数组单元用来存储状态)。
        DFS:对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理速度迅速,然而在深度很大的情况下效率不高

总结:不管是BFS还是DFS,它们虽然好用,但由于时间和空间的局限性,以至于它们只能解决数据量小的问题。
转载于:https://www.cnblogs.com/wangmengmeng/p/4843225.html

其实大家也能明白,还得靠实际情况去选择;至于复杂的题目,那就另请高明采用跟高级的算法吧。

三、上代码

注释

8*8的计算太耗时了,先将棋盘设置为4*5,输出都是32。如果想改变棋盘大小,修改m、n即可(数据请阳间一点,我是新手,程序健壮性不强)。另外,如果m、n较大,bfs中ox、oy、id的数组大小也要调大(参考:bfs中,当m=4,n=5时,数组应不少于35661;在每个while循环中输出tail的值即可知数组的使用情况)

1.bfs

program bfsOfKnight;
const
        //Set size
        m=4;n=5;
        //Eight directions
        dx:array[1..8] of -2..2=(-2,-2,-1,-1,1,1,2,2);
        dy:array[1..8] of -2..2=(1,-1,2,-2,2,-2,1,-1);
var
        x,y,head,tail,i,j,step,h,t,k:longint;
        ox,oy,id:array[1..100000] of longint;
        f:boolean;
begin
        //The fist point is (1,1)
        head:=1;tail:=1;
        ox[1]:=1;oy[1]:=1;id[1]:=0;
        while (tail>=head) do
                begin
                        //Have we succeeded? If so,there is no need to search
                        if step=m*n-1 then begin writeln(tail-head+1);exit;end;
                        h:=head;t:=tail;
                        for i:=h to t do
                                begin
                                        x:=ox[i];y:=oy[i];
                                        for j:=1 to 8 do
                                                begin
                                                        //Jump to somewhere
                                                        x:=x+dx[j];y:=y+dy[j];
                                                        //Judge whether the place is OK
                                                        k:=i;f:=false;
                                                        while k>=1 do
                                                                begin
                                                                        if (ox[k]=x) and (oy[k]=y) then
                                                                                begin
                                                                                        f:=true;
                                                                                        break;
                                                                                end;
                                                                        k:=id[k];
                                                                end;
                                                        if f=true then
                                                                begin
                                                                        //Jump back,prepare for jumping to another place in next step
                                                                        x:=x-dx[j];y:=y-dy[j];
                                                                        continue;
                                                                end;
                                                        if (x>0) and (x<=m) and (y>0) and (y<=n) then
                                                                begin
                                                                        //Now we have searched this place,recoed it
                                                                        inc(tail);
                                                                        ox[tail]:=x;oy[tail]:=y;
                                                                        //Record where it is from
                                                                        id[tail]:=i
                                                                end;
                                                        //Jump back,prepare for jumping to another place in next step
                                                        x:=x-dx[j];y:=y-dy[j];
                                                end;
                                        //Clean places that we have checked
                                        inc(head);
                                end;
                        inc(step);
                end;
end.

输出

32

2.dfs

program dfsOfKnight;
const
        //Set size
        m=4;n=5;
        //Eight directions
        dx:array[1..8] of -2..2=(-2,-2,-1,-1,1,1,2,2);
        dy:array[1..8] of -2..2=(1,-1,2,-2,2,-2,1,-1);
var
        way,i,j:longint;
        flag:array[1..m,1..n] of boolean;
        f:boolean;
procedure dfs(step,xx,yy:longint);
        var
                x,y,i:longint;
        begin
                //Should we stop?
                if f=true then exit;
                //We got it?
                if step=n*m-1  then
                        begin
                                inc(way);
                                //Tell other procedures to stop
                                f:=true;
                                //Stop dps
                                exit;
                        end;
                //Deeper and deeper
                for i:=1 to 8 do
                        begin
                                x:=xx+dx[i];y:=yy+dy[i];
                                //Is this place OK?
                                if (x>0) and (x<=m) and (y>0) and (y<=n) and (flag[x,y]=false) then
                                        begin
                                                //We have been to here
                                                flag[x,y]:=true;
                                                //Keep deeper
                                                dfs(step+1,x,y);
                                                //Prepare for the next step
                                                flag[x,y]:=false;
                                        end;
                        end;
                f:=false;
        end;
begin
        //A new search have begun.Make everything new
        //Clean the marks
        fillchar(flag,sizeof(flag),false);f:=false;
        //We can't go to (1,1)
        flag[1,1]:=true;
        //Start dps
        dfs(0,1,1);
        writeln(way);
end.

输出

32

四、结语

不难看出深搜广搜思路完全不同,但殊途同归。对于二者应完全掌握并熟练运用。

如果有误,欢迎大佬指出,臣不胜受恩感激:P

PS:dfs中略加修改可以输出每一种情况的具体走法,不知道bfs可不可以,求指导

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值