zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Git 自救指南:这些坑你都跳得出吗?
    敢不敢模拟超过 5 万的并发用户?
    一条简单的 SQL 执行超过 1000ms,纳尼?
    JVM 最多支持多少个线程?
    19 条效率至少提高 3 倍的 MySQL 技巧
    LeetCode 剑指offer 面试题04. 二维数组中的查找
    LeetCode 剑指offer 面试题03 数组中重复的数字
    东华大学计算机软件工程 复试最后一百题
    东华大学计算机软件工程复试 挑战练习
    东华大学计算机软件工程复试 进阶练习
  • 原文地址:https://www.cnblogs.com/Sakits/p/5766953.html
Copyright © 2011-2022 走看看