程设2021期末题G:小C的泳池

原题:http://cxsjsx.openjudge.cn/2021finalpractise/G/

描述

小C在一个排水系统不太好的学校上学。又是一个下雨天,学校里高低不平积了很多水。小C突发奇想:如果大雨一直下,多久以后我可以在学校里游泳呢?
学校是 N x N 的坐标方格 grid 中,每一个方格的值 grid(i,j)表示在位置 (i,j) 的高度。现在开始下雨了。当时间为 t 时,此时雨水导致方格中任意位置的水位为 t 。你可以从一个方格游向四周相邻的任意一个方格,但是前提是此时水位必须同时淹没这两个方格。假定小C的游动是不耗时的。
现在小C从坐标方格的左上(0,0)出发。最少耗时多久他才能到达坐标方格的右下平台 (N-1, N-1)?

输入

第一行有一个整数N,以下是一个N*N的方阵,代表各处的高度。
输入范围:
2 ≤ N ≤ 300
0 ≤ Height ≤ 10000000

输出

输出一个整数,代表最少等待时间T

样例输入

样例输入1:
2
0 2
1 3

样例输入2:
5
0 1 2 3 4
24 23 22 21 5
12 13 14 15 16
11 17 18 19 20
10 9 8 7 6

样例输出

样例输出1:
3

样例输出2:
16

解法

这道题长着迷宫的样子,但是与迷宫无关,转换一下题意,问的就是从(0,0)到(N-1,N-1)的各条路径最大值中的最小值。

一开始尝试了深搜和广搜但是都TLE了,试图使用记忆性递归式的动态规划,但是此处不能用动态规划,因为不满足无后效性,不同的路径最大值不同。

这道题正确的思路是用二分来做,L是方格中的最小值,R是最大值,二分尝试能否到达右下角。(果然一直超时的时候应该想想二分

在尝试能否到达右下角的时候采用了染色的思想,还是加入了广搜。应该有更简便的写法。

AC代码如下:

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 using namespace std;
 6 int maze[305][305];
 7 bool reach[305][305];
 8 int dx[4] = { -1,1,0,0 };
 9 int dy[4] = { 0,0,-1,1 };
10 int N;
11 struct point {
12     int x, y;
13     point(int a,int b):x(a),y(b){}
14 };
15 bool canreach(int t) {
16     if (maze[0][0] > t)
17         return false;
18     memset(reach, 0, sizeof(reach));
19     reach[0][0] = 1;
20     queue<point>myqueues;
21     myqueues.push(point(0, 0));
22     while (!myqueues.empty()) {
23         point top = myqueues.front();
24         myqueues.pop();
25         if (top.x == N - 1 && top.y == N - 1)
26             return true;
27         for (int i = 0; i < 4; i++) {
28             int tx = top.x + dx[i];
29             int ty = top.y + dy[i];
30             if (tx < 0 || tx >= N || ty < 0 || ty >= N)
31                 continue;
32             if (reach[tx][ty])
33                 continue;
34             if (maze[tx][ty] > t)
35                 continue;
36             reach[tx][ty] = 1;
37             myqueues.push(point(tx, ty));
38         }
39     }
40     return false;
41 }
42 int main() {
43     memset(maze, 0, sizeof(maze));
44     cin >> N;
45     int L = 10000000, R = 0;
46     for (int i = 0; i < N; i++) {
47         for (int j = 0; j < N; j++) {
48             cin >> maze[i][j];
49             L = min(maze[i][j], L);
50             R = max(maze[i][j], R);
51         }
52     }
53     int result= 10000000;
54     while (L <= R) {
55         int mid = (L + R) / 2;
56         if (canreach(mid)) {
57             R = mid - 1;
58             result = min(result, mid);
59         }
60         else
61             L = mid + 1;
62     }
63     cout << result << endl;
64     return 0;
65 }

 

 
posted @ 2021-07-20 11:11  永远是个小孩子  阅读(574)  评论(0)    收藏  举报