Rqnoj335 流星雨 题解

      又是搜索。这几天做了不少搜索题,对搜索题的脉络也有了一些新的理解。

      从我做的屈指可数的题目里面我发现,DFS的题相对于BFS来说更加灵活。比如“著名”的“24点”这道题,递归调用的方法很是神奇(或许我太弱小了…),而BFS的形式却相对单一,但是有时候却需要我们的一些灵活的思维(参见本Blog“无边界BFS处理办法”一文)。这道题就是运用灵活的思维处理BFS问题的又一例子。

 

【题目描述】(略改编自rqnoj335)

      Saltless听说有一场壮丽的流星雨即将来临,而且据说陨石将要落下来撞击地球并摧毁一切它遇到的东西。为了保证自己的安全,Saltless决定到一个安全的(永远不会被陨石击毁)地方去。

      报道表明将有M颗陨石落下(1 ≤ M ≤ 50,000),第i个陨石将在Ti(0 ≤ Ti ≤ 1,000)时刻砸中(Xi,Yi)点(0 ≤ Xi ≤ 300; 0 ≤ Yi ≤ 300) 。每颗陨石将击毁它直接砸中的点以及四个与其直接相邻的点。

      他现在所处的地方是坐标系的原点,并从零时刻起出发,前往一个安全的地点,要求是他经过某点时该点未被击毁。他只能在坐标系的第一象限以及x,y轴的正半轴上活动。

      求他能到达一个安全地点的最短时间。



【输入格式】

第一行:陨石个数M

第二行至第M+1行:第i+1行有三个整数表示:Xi,Yi,和Ti

数据范围见题目描述



【输出格式】

输出只有一行,即Saltless所需的最短时间。如果他永远无法到达一个安全的地方,输出-1



【样例输入】

4

0 0 2

2 1 2

1 1 2

0 3 5



【样例输出】

5

      这道题与传统BFS的不同在于,传统的BFS题中的障碍物(也就是本题中的陨石坑)是静止的,从一开始就在,不会消失。而这道题的障碍物却是“动态”的,并不是存在于整个过程。这就需要我们的一些“创新”的思维。

      我们知道,整个世界只有Saltless一个人,没有人为他填好陨石坑——也就是说,陨石坑一旦存在,就不会消失。所以,我们没有必要记录下每一块陨石撞击的时间,只用找到每个坐标最早被砸到的时间,在那个时间之前从那里经过就行了。

      我们用t数组记录点(i,j)不能走的最小时间,同时更新“四个与其直接相邻的点”的t值,然后在f数组中把会被砸到的点标记。这样,我们在BFS中一旦找到一个没有标记过的点,就可以输出步数,在那里悠闲地看流星雨啦~

      另外,注意题目中的描述,Saltless可以在坐标轴上走,而且地图的大小没有限制。所以301那一圈也要考虑。

 

      参考代码:

  
    
1 program meteor;
2 const
3 dx: array [ 1 .. 4 ] of integer = ( 0 , 0 , 1 , - 1 );
4 dy: array [ 1 .. 4 ] of integer = ( 1 , - 1 , 0 , 0 );
5 type l = record
6 x,y:longint;
7 dist:longint;
8 end ;
9 var
10 i,j,k,n:longint;
11 fa,s:longint;
12 xx,yy,xt,yt:integer;
13 t: array [ 0 .. 301 , 0 .. 301 ] of longint;
14 v: array [ 0 .. 301 , 0 .. 301 ] of boolean;
15 f: array [ 0 .. 301 , 0 .. 301 ] of boolean;
16 d: array [ 1 .. 100000 ] of l;
17 begin
18 assign(input, ' metor.in ' );
19 reset(input);
20 assign(output, ' metor.out ' );
21 rewrite(output);
22 readln(n);
23 fillchar(f,sizeof(f),false);
24 fillchar(v,sizeof(v),false);
25 for i: = 1 to n do
26 begin
27 readln(xx,yy,k);
28 if (t[xx,yy] > k) or (t[xx,yy] = 0 ) then // 记录该点最短时间
29 begin
30 t[xx,yy]: = k;
31 f[xx,yy]: = true;
32 end ;
33 for j: = 1 to 4 do // 更新相关四点最短时间
34 begin
35 xt: = xx + dx[j];
36 yt: = yy + dy[j];
37 if (xt >= 0 ) and (xt <= 301 ) and (yt <= 301 ) and (yt >= 0 ) then
38 if (t[xt,yt] > k) or (t[xt,yt] = 0 ) then
39 begin
40 t[xt,yt]: = k;
41 f[xt,yt]: = true;
42 end ;
43 end ;
44 end ;
45 fa: = 1 ;
46 s: = 1 ;
47 d[ 1 ].x: = 0 ;
48 d[ 1 ].y: = 0 ;
49 d[ 1 ].dist: = 0 ;
50 v[ 0 , 0 ]: = true;
51 while fa <= s do
52 begin
53 for i: = 1 to 4 do
54 begin
55 xx: = d[fa].x + dx[i];
56 yy: = d[fa].y + dy[i];
57 if (xx >= 0 ) and (xx <= 301 ) and (yy >= 0 ) and (yy <= 301 ) then
58 if not v[xx,yy] then
59 begin
60 if (f[xx,yy]) and (t[xx,yy] > d[fa].dist + 1 ) then
61 begin // 如果会被砸到,判断当前时间该点是否可走,如果能走就记录下来
62 inc(s);
63 d[s].x: = xx;
64 d[s].y: = yy;
65 d[s].dist: = d[fa].dist + 1 ;
66 v[xx,yy]: = true;
67 end ;
68 if not f[xx,yy] then // 如果安全,就直接输出
69 begin
70 writeln(d[fa].dist + 1 );
71 close(input);
72 close(output);
73 halt;
74 end ;
75 end ;
76 end ;
77 inc(fa);
78 end ;
79 writeln( ' -1 ' );
80 close(input);
81 close(output);
82 end .

 

 

(Saltless原创,转载请注明出处)

你可能感兴趣的:(题解)