bzoj1656: [Usaco2006 Jan] The Grove 树木 (bfs+新姿势)

    题目大意:一个n*m的图中,“.”可走,“X”不可走,“*”为起点,问从起点开始绕所有X一圈回到起点最少需要走多少步。

      一开始看到这题,自己脑洞了下怎么写,应该是可过,然后跑去看了题解,又学会了一个新姿势。。。

     

 

       上图是样例,红色笔迹是走法,需要走13步。

      这显然是bfs题,问题是怎么让bfs绕这坨东西一圈,非常巧妙的思路,从任意一个X节点画一条射线与边界垂直,如下图所示。

      

 

       当我们从右向左bfs的时候碰到这条线,就停止bfs;当我们绕了一圈从左向右bfs的时候碰到这条线,我们就继续走。

      dist[1][x][y]表示从左向右经过这条线之后起点到(x,y)的最短距离,dist[0][x][y]表示没有经过这条线,起点到(x,y)的最短距离。当我们从左向右经过这条线后的bfs我们就只更新dist[1][x][y],最后输出的就是dist[1][起点x][起点y]。

代码如下:

const
  dx:array[1..8]of integer=(1,0,-1,0,1,1,-1,-1);
  dy:array[1..8]of integer=(0,1,0,-1,1,-1,1,-1);
var
  n,m,i,j,fx,fy,tx,ty:longint;
  s:string;
  line,map:array[0..50,0..50]of boolean;
  dist:array[0..1,0..50,0..50]of longint;
  v:array[0..1,0..50,0..50]of boolean;
  h:array[0..1000000,1..3]of longint;

procedure bfs;
var
  i,j,k,front,rear,nx,ny,xx,yy,flag,flag2:longint;
begin
  for i:=1 to n do for j:=1 to m do for k:=0 to 1 do dist[k,i,j]:=23333333;
  dist[0,fx,fy]:=0;v[0,fx,fy]:=true;front:=0;rear:=1;h[1,1]:=fx;h[1,2]:=fy;h[1,3]:=0;
  while front<>rear do
  begin
    inc(front);
    nx:=h[front,1];ny:=h[front,2];flag:=h[front,3];
    if front=1000 then front:=0;
    for i:=1 to 8 do
    begin
      xx:=nx+dx[i];yy:=ny+dy[i];
      if (xx<0)or(xx>n)or(yy<0)or(yy>m)or(map[xx,yy])or((line[xx,yy] or line[nx,ny])and(yy<=ny))then continue;
      if (line[xx,yy])or(flag=1) then flag2:=1 else flag2:=0;
      if dist[flag,nx,ny]+1<dist[flag2,xx,yy] then
      begin
        dist[flag2,xx,yy]:=dist[flag,nx,ny]+1;
        if not v[flag2,xx,yy] then
        begin
          v[flag2,xx,yy]:=true;
          if rear=1000 then rear:=0;
          inc(rear);
          h[rear,1]:=xx;
          h[rear,2]:=yy;
          h[rear,3]:=flag2;
        end;
      end;
    end;
    v[flag,nx,ny]:=false;
  end;
  writeln(dist[1,fx,fy]);
end;

begin
  readln(n,m);
  for i:=1 to n do
  begin
    readln(s);
    for j:=1 to m do
    begin
      if s[j]='*' then
      begin
        fx:=i;fy:=j;
      end;
      if s[j]='X' then
      begin
        tx:=i;ty:=j;
        map[i,j]:=true;
      end;
    end;
  end;
  for i:=tx to n do
  line[i,ty]:=true;
  bfs;
end.
View Code
posted @ 2016-08-12 23:28  Sakits  阅读(350)  评论(0编辑  收藏  举报