题解 P1141 【01迷宫】

Fading

2017-11-06 18:19:47

Solution

**这道题真的把我气的......** 一开始:不就是BFS嘛! 后来:怎么0分? 再后来:T了3个! 最后:还是用记忆化BFS吧! 先讲讲最水的思路: **一个一个格子广搜,开一个队列记录一些搜过的坐标。** ```cpp procedure bfs(x0,y0:longint); var dl:array[1..100000,1..2] of longint; i,j,x,y,h,t:longint; begin h:=0; t:=1; dl[1,1]:=x0; dl[1,2]:=y0; o:=1;//记录可以到几个点,别忘记了自己! for i:=1 to n do for j:=1 to n do hash[i,j]:=false;//记录这个点是否走过,不然会死循环+答案错误 hash[x0,y0]:=true; repeat inc(h); for i:=1 to 4 do begin x:=dx[i]+dl[h,1]; //dx、dy表示上下左右的x、y变化量 y:=dy[i]+dl[h,2]; if (map[x,y]=map[dl[h,1],dl[h,2]]) //如果与之前的数一样,不可以走,退出~ or (x=0) or (y=0) or (x=n+1) or (y=n+1) or hash[x][y] //判断边界以及是否走过 then continue; inc(t); dl[t,1]:=x; dl[t,2]:=y; hash[x,y]:=true; inc(o); end; until h>=t; end; ``` 然后就华丽丽的T了3个点。。。 原来把hash赋值的时候太耗时了... 看来以后不要使用fillchar(memset)了,太费时间了 只需要在最后的时候改一下即可 for i:=1 to h do hash[dl[i][1],dl[i][2]]:=false; 更快更省时! 然而只有80分,还有两个T! 忍无可忍的我只能用记忆化了。。。 因为题目让我们求可以跳到多少个点,所以一次BFS下来,所有队列中的点可以到达的点数都是最终求出的结果(即为o) 那么一次BFS可以顺带求出很多点的答案了。 ```cpp for i:=1 to h do begin as[dl[i][1],dl[i][2]]:=false; jiyi[dl[i][1],dl[i][2]]:=o;//记忆化 end; ``` 完整代码如下: ```cpp const dx:array[1..4] of longint=(0,1,0,-1); dy:array[1..4] of longint=(-1,0,1,0); var i,j,k,o,p,m,n,b,g,q1,q2:longint; map,jiyi:array[0..1005,0..1005] of longint; s:ansistring; as:array[0..1[001,0..1001] of boolean; procedure bfs(x0,y0:longint); var dl:array[1..200001,1..2] of longint; i,j,x,y,h,t:longint; begin h:=0; t:=1; dl[1,1]:=x0; dl[1,2]:=y0; o:=1; as[x0,y0]:=true; repeat inc(h); for i:=1 to 4 do begin x:=dx[i]+dl[h,1]; y:=dy[i]+dl[h,2]; if (map[x,y]=map[dl[h,1],dl[h,2]]) or (x=0) or (y=0) or (x=n+1) or (y=n+1) ``` or as[x][y] ```cpp then continue; inc(t); dl[t,1]:=x; dl[t,2]:=y; as[x,y]:=true; inc(o); end; until h>=t; for i:=1 to h do begin as[dl[i][1],dl[i][2]]:=false; jiyi[dl[i][1],dl[i][2]]:=o; end; end; begin readln(n,m); for i:=1 to n do begin readln(s); for j:=1 to length(s) do map[i,j]:=ord(s[j])-48;//注意一下,这里需要字符串处理!!! end; for i:=1 to n do for j:=1 to n do jiyi[i,j]:=-1; for i:=1 to m do begin readln(q1,q2); if jiyi[q1,q2]<>-1 then begin writeln(jiyi[q1,q2]); continue; end;//如果这个点在之前已经(顺带)求过了,那么直接输出! bfs(q1,q2); //广搜 writeln(o); //输出 end; end. ```