778. Swim in Rising Water

▶ 给定方阵 grid,其元素的值为 D0n-1,代表网格中该点处的高度。现在网格中开始积水,时刻 t 的时候所有值不大于 t 的格点被水淹没,当两个相邻格点(上下左右四个方向)的值都不超过 t 的时候我们称他们连通,即可以通过游泳到达,请问能将主对角两顶点((0, 0) 和 (n-1, n-1))连通的最小时刻是多少?例如 下图的最小连通时间为 16 。

  

● 自己的代码,22 ms,简单 BFS,普通队列

 1 class Solution
 2 {
 3 public:
 4     int swimInWater(vector<vector<int>>& grid)//set a binary search to find a proper moment
 5     {
 6         const int n = grid.size();
 7         int lp, rp, mp;
 8         for (lp = max(2 * n - 2, max(grid[0][0], grid[n - 1][n - 1])) - 1, rp = n * n, mp = (lp + rp) / 2; lp < rp && mp > lp; mp = (lp + rp) / 2)
 9         {                       // 时间最小是 2n-2,最大是 n^2-1
10             if (swim(grid, mp))
11                 rp = mp;
12             else
13                 lp = mp;
14         }
15         return rp;
16     }
17     bool swim(vector<vector<int>>& grid, int time)// swimming at the moment 'time', can I reach the point (n-1, n-1)?
18     {
19         const int n = grid.size();
20         vector<vector<bool>> table(n, vector<bool>(n, false));
21         queue<vector<int>> qq;
22         vector<int> temp;
23         int row, col;
24         for (qq.push({ 0, 0 }), table[0][0] = true; !qq.empty();)
25         {
26             temp = qq.front(), qq.pop(), row = temp[0], col = temp[1];
27             if (row == n - 1 && col == n - 1)
28                 return true;
29 
30             if (row > 0 && grid[row - 1][col] <= time && !table[row - 1][col])// up
31                 qq.push({ row - 1, col }), table[row - 1][col] = true;
32             if (col > 0 && grid[row][col - 1] <= time && !table[row][col - 1])// left
33                 qq.push({ row, col - 1 }), table[row][col - 1] = true;
34             if (row < n - 1 && grid[row + 1][col] <= time && !table[row + 1][col])// down
35                 qq.push({ row + 1, col }), table[row + 1][col] = true;
36             if (col < n - 1 && grid[row][col + 1] <= time && !table[row][col + 1])// right
37                 qq.push({ row, col + 1 }), table[row][col + 1] = true;
38         }
39         return false;
40     }
41 };

● 大佬的代码,13 ms,DFS,注意这里使用了一个数组 dir 来决定搜索方向,比较有趣的用法

 1 class Solution
 2 {
 3 public:
 4     int swimInWater(vector<vector<int>>& grid)
 5     {
 6         const int n = grid.size();
 7         int lp, rp, mp;
 8         for (lp = grid[0][0], rp = n * n - 1; lp < rp;) 
 9         {
10             mp = lp + (rp - lp) / 2;
11             if (valid(grid, mp))
12                 rp = mp;
13             else
14                 lp = mp + 1;
15         }
16         return lp;
17     }
18     bool valid(vector<vector<int>>& grid, int waterHeight)
19     {
20         const int n = grid.size();
21         const vector<int> dir({ -1, 0, 1, 0, -1 });
22         vector<vector<bool>> visited(n, vector<bool>(n, 0));        
23         return dfs(grid, visited, dir, waterHeight, 0, 0, n);
24     }
25     bool dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, vector<int>& dir, int waterHeight, int row, int col, int n)
26     {
27         int i, r, c;
28         visited[row][col] = true;
29         for (i = 0; i < 4; ++i)
30         {
31             r = row + dir[i], c = col + dir[i + 1];
32             if (r >= 0 && r < n && c >= 0 && c < n && visited[r][c] == false && grid[r][c] <= waterHeight)
33             {
34                 if (r == n - 1 && c == n - 1)
35                     return true;
36                 if (dfs(grid, visited, dir, waterHeight, r, c, n))
37                     return true;
38             }
39         }
40         return false;
41     }
42 };

● 大佬的代码,185 ms,DP + DFS,维护一个方阵 dp,理解为“沿着当前搜索路径能够到达某一格点的最小时刻”,初始假设 dp = [INT_MAX] ,即所有的格点都要在 INT_MAX 的时刻才能到达,深度优先遍历每个点,不断下降每个点的值(用该点原值和用于遍历的临时深度值作比较,两者都更新为他们的较小者)

 1 class Solution
 2 {
 3 public:
 4     int swimInWater(vector<vector<int>> &grid)
 5     {
 6         const int m = grid.size();
 7         vector<vector<int>> dp(m, vector<int>(m, INT_MAX));
 8         helper(grid, 0, 0, 0, dp);
 9         return dp[m - 1][m - 1];
10     }
11     void helper(vector<vector<int>> &grid, int row, int col, int deep, vector<vector<int>> &dp)
12     {
13         const int m = grid.size();
14         int i, x, y;
15         deep = max(deep, grid[row][col]);
16         if (dp[row][col] <= deep)
17             return;
18         for (dp[row][col] = deep, i = 0; i < direction.size(); i++)
19         {
20             x = row + direction[i][0], y = col + direction[i][1];
21             if (x >= 0 && x < m && y >= 0 && y < m)
22                 helper(grid, x, y, dp[row][col], dp);
23         }
24     }
25     vector<vector<int>> direction = { { -1, 0 },{ 1, 0 },{ 0, 1 },{ 0, -1 } };
26 };

● 大佬的代码,18 ms,DFS,优先队列,Dijkstra算法,相当于在搜索队列中,总是优先研究最小时刻的点

 1 class Solution
 2 {
 3 public:
 4     int swimInWater(vector<vector<int>>& grid)
 5     {
 6         const int n = grid.size();
 7         const vector<int> dir({ -1, 0, 1, 0, -1 });
 8         int ans, i, r, c;
 9         priority_queue<vector<int>, vector<vector<int>>, greater<vector<int>>> pq;
10         vector<vector<bool>> visited(n, vector<bool>(n, false));
11         vector<int> cur;
12         for (visited[0][0] = true, ans = max(grid[0][0], grid[n - 1][n - 1]), pq.push({ ans, 0, 0 }); !pq.empty();)
13         {
14             cur = pq.top(),pq.pop(), ans = max(ans, cur[0]);
15             for (i = 0; i < 4; i++)
16             {
17                 r = cur[1] + dir[i], c = cur[2] + dir[i + 1];
18                 if (r >= 0 && r < n && c >= 0 && c < n && visited[r][c] == false)
19                 {
20                     visited[r][c] = true;
21                     if (r == n - 1 && c == n - 1)
22                         return ans;
23                     pq.push({ grid[r][c], r, c });                    
24                 }
25             }
26         }
27         return -1;
28     }
29 };

● 大佬的代码,11 ms,使用那个 DP + DFS 解法的深度更新思路,把搜索方式换成 BFS

 1 class Solution
 2 {
 3 public:
 4     int swimInWater(vector<vector<int>>& grid)
 5     {
 6         const int n = grid.size();
 7         const vector<int> dir({ -1, 0, 1, 0, -1 });
 8         int ans, i, r, c;
 9         vector<vector<bool>> visited(n, vector<bool>(n, false));
10         priority_queue<vector<int>, vector<vector<int>>, greater<vector<int>>> pq;
11         vector<int> cur;         
12         queue<pair<int, int>> myq;        
13         pair<int, int> p;
14         for (visited[0][0] = true, ans = max(grid[0][0], grid[n - 1][n - 1]), pq.push({ ans, 0, 0 }); !pq.empty();)
15         {
16             cur = pq.top(), pq.pop(), ans = max(ans, cur[0]);
17             for (myq.push({ cur[1], cur[2] }); !myq.empty();)
18             {
19                 p = myq.front(), myq.pop();
20                 if (p.first == n - 1 && p.second == n - 1) 
21                     return ans;
22                 for (i = 0; i < 4; ++i)
23                 {
24                     r = p.first + dir[i], c = p.second + dir[i + 1];
25                     if (r >= 0 && r < n && c >= 0 && c < n && visited[r][c] == 0)
26                     {
27                         visited[r][c] = true;
28                         if (grid[r][c] <= ans)
29                             myq.push({ r, c });
30                         else
31                             pq.push({ grid[r][c], r, c });
32                     }
33                 }
34             }
35         }
36         return -1;
37     }
38 };

▶ 附上一个测试数据,答案为 266

 1 { 
 2     {105, 209, 171, 91, 64, 394, 279, 11, 45, 84, 207, 321, 216, 197, 381, 377, 78, 19, 203, 198},
 3     { 141, 10, 335, 170, 265, 104, 338, 40, 397, 376, 346, 356, 212, 154, 280, 177, 247, 90, 87, 360 },
 4     { 99, 59, 242, 149, 344, 172, 276, 230, 133, 193, 284, 345, 46, 363, 30, 142, 295, 70, 224, 200 },
 5     { 251, 88, 379, 72, 319, 272, 243, 165, 180, 182, 387, 264, 23, 67, 137, 342, 125, 139, 144, 367 },
 6     { 94, 211, 151, 37, 290, 112, 343, 157, 300, 271, 260, 373, 369, 294, 289, 57, 44, 12, 20, 340 }, 
 7     { 220, 368, 186, 277, 181, 187, 273, 214, 315, 337, 328, 18, 231, 223, 331, 75, 275, 96, 135, 150 },
 8     { 202, 74, 27, 184, 399, 341, 49, 62, 261, 86, 314, 383, 302, 257, 61, 148, 268, 120, 36, 25 },
 9     { 15, 253, 285, 185, 226, 146, 126, 122, 83, 361, 110, 234, 183, 239, 52, 190, 152, 81, 136, 188 },
10     { 39, 199, 358, 26, 301, 116, 32, 386, 29, 138, 393, 159, 102, 140, 370, 227, 282, 111, 5, 33 },
11     { 189, 35, 132, 54, 210, 235, 28, 353, 281, 127, 318, 58, 100, 286, 384, 24, 307, 252, 80, 103 }, 
12     { 244, 176, 124, 79, 161, 355, 218, 398, 392, 380, 225, 121, 178, 352, 329, 322, 167, 51, 313, 85 }, 
13     { 107, 118, 351, 287, 324, 283, 48, 320, 82, 364, 357, 16, 219, 330, 89, 143, 241, 262, 71, 191 }, 
14     { 95, 97, 3,7, 270, 249, 213, 339, 362, 298, 4, 258, 248, 390, 299, 306, 156, 164, 109, 229 }, 
15     { 221, 9, 228, 160, 274, 263, 374, 147, 98, 63, 13, 41, 326, 396, 349, 372, 385, 317, 325, 266 },
16     { 53, 131, 173, 312, 174, 114, 250, 119, 163, 22, 246, 92, 278, 365, 292, 215, 14, 304, 204, 73 },
17     { 233, 323, 366, 130, 378, 305, 311, 93, 134, 217, 297, 327, 232, 194, 240, 1, 208, 6, 310, 47 }, 
18     { 69, 101, 332, 195, 254, 236, 50, 166, 56, 168, 267, 17, 359, 347, 65, 316, 238, 296, 348, 222 },
19     { 76, 123, 129, 293, 391, 2, 245, 108, 303, 38, 66, 55, 43, 256, 162, 60, 179, 77, 336, 21 },
20     { 196, 388, 333, 395, 42, 382, 291, 237, 288, 375, 128, 145, 192, 158, 350, 259, 206, 34, 334, 255 }, 
21     { 201, 175, 153, 68, 205, 155, 115, 269, 389, 169, 371, 308, 117, 31, 354, 8, 113, 309, 106, 0 }
22 };
原文地址:https://www.cnblogs.com/cuancuancuanhao/p/8419569.html