题解 P1443 【马的遍历】

· · 题解

这里给大家小小的普及一下广搜。(建议先掌握深搜)个人觉得luogu里这题可以用来入门。

深搜与广搜的搜索模式

首先,我们就这道题而言,深搜的话,应该是这样:

尝试8个方向的一个->尝试新坐标8个方向的一个->…………->返回尝试下一个方向……

也就是说,作为一棵树,我们先尝试一个分支,没分支了再返回寻找下一个分支继续。于是可以用来穷举所以情况。

这里吐槽一句,我第一次不知不觉写成深搜了。。。ovo。

但是广搜我们知道它可以用来找到最小路径。。我们看一下它的搜索过程:

尝试8个方向的一个->尝试8个方向的另一个……尝试完所有八个方向,从新的八个坐标开始……搜索到结果,结束。

也就是说,作为一棵树,我们先尝试完所有第一层,第二层,知道找到答案为止,这样可以找到最短路径,为什么呢,假设这个马走到X,Y要跳3步,我们先尝试了所有走零步,一步,两步的情况,所以在第三步的情况搜索到的就是最优答案。

广搜的代码模式

我讲的不是很清楚,上面建议先看过其他广搜材料的再看看。

现在讲一下广搜的代码模式

首先说明,尽管广搜概念上看起来很像需要递归,但实际上这样应该是写不出来的,或者写着写着就写成深搜了。。

因为实际上广搜是靠队列进行的个人概念弄懂后代码还是一脸懵比,所以来讲一下这个代码模式,希望对大家有帮助。

首先,我们需要一个队列,其实就是一个数组。还需要两个变量,就b,t吧,代表队列头和队列尾。

我们把马看做一个点,有八个方向可以走,我们就扩展八个节点,同时用一个while循环来控制搜索,条件b<=t,意思是队列不是空的时候进行。

什么叫队列不为空呢?其实在搜索过程中,我们会不断扩展队列尾,但是队列头用过之后我们就会+1,这样当所有节点扩展完后,队列搜完就是全部搜完了。其实就是把要搜索的节点全找出来,同时一个一个搜过去。

之后扩展节点并且加入队列,就完成了。

注意

1.队列要开大一点

2.需要有一个结构,分别是x,y和步数

3.由于广搜不需要回溯,故要有一个数组标记已走过的点

代码

type
  dl=record
    x,y,bs:longint;//x,y,step
  end;

var sc,bz:array[1..1000,1..1000]of longint;//输出,标志
  cd:array[1..50000]of dl;//队列
  fx:array[1..8,1..2]of longint=((2,1),(2,-1),(-2,1),(-2,-1),(1,2),(1,-2),(-1,2),(-1,-2));//八个方位
  n,m,i,j,qx,qy:longint;//棋盘长,宽,计数ij,起点坐标
  te:ansistring;

procedure search(x,y:longint);
var hx,hy:longint;//变化后x,y
  b,e,k:longint;//begin,end,计数
begin
  b:=1;e:=1;
  cd[1].bs:=0;
  cd[1].x:=x;
  cd[1].y:=y;
  while(b<=e)do begin
    for k:=1 to 8 do begin
      hx:=cd[b].x+fx[k][1];
      hy:=cd[b].y+fx[k][2];
      if(hx>=1)and(hx<=n)and(hy>=1)and(hy<=m)and(bz[hx,hy]=0)then begin
        inc(e);
        bz[hx,hy]:=1;
        cd[e].x:=hx;
        cd[e].y:=hy;
        cd[e].bs:=cd[b].bs+1;
        sc[hx,hy]:=cd[e].bs;
      end;
    end;
    inc(b);
  end;
  exit;
end;

begin
  readln(n,m,qx,qy);
  fillchar(bz,sizeof(bz),0);
  search(qx,qy);

  for i:=1 to n do begin
  for j:=1 to m do begin
    if(sc[i,j]=0)then
    sc[i,j]:=-1;
  end;

  sc[qx,qy]:=0;

  end;
  for i:=1 to n do begin
  for j:=1 to m do begin
     str(sc[i,j],te);                         //感谢 @hz1624917200 的输出优化方案
     write(te,'':5-length(te));
   end;
      writeln;
   end;
  readln;readln;
end.