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
  • 相关阅读:
    解决ListView异步加载数据之后不能点击的问题
    android点击实现图片放大缩小 java技术博客
    关于 数据文件自增长 的一点理解
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Linux 超级用户的权利
    RAC 实例 迁移到 单实例 使用导出导入
    Shell 基本语法
    Linux 开机引导与关机过程
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Oracle RAC + Data Guard 环境搭建
  • 原文地址:https://www.cnblogs.com/Sakits/p/5766953.html
Copyright © 2011-2022 走看看