题目大意:一个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.
时间: 2024-10-02 21:30:39