[LeetCode] Contain Virus 包含病毒


 

A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls.

The world is modeled as a 2-D array of cells, where 0 represents uninfected cells, and 1 represents cells contaminated with the virus. A wall (and only one wall) can be installed between any two 4-directionally adjacent cells, on the shared boundary.

Every night, the virus spreads to all neighboring cells in all four directions unless blocked by a wall. Resources are limited. Each day, you can install walls around only one region -- the affected area (continuous block of infected cells) that threatens the most uninfected cells the following night. There will never be a tie.

Can you save the day? If so, what is the number of walls required? If not, and the world becomes fully infected, return the number of walls used.

 

Example 1:

Input: grid = 
[[0,1,0,0,0,0,0,1],
 [0,1,0,0,0,0,0,1],
 [0,0,0,0,0,0,0,1],
 [0,0,0,0,0,0,0,0]]
Output: 10
Explanation:
There are 2 contaminated regions.
On the first day, add 5 walls to quarantine the viral region on the left. The board after the virus spreads is:

[[0,1,0,0,0,0,1,1],
 [0,1,0,0,0,0,1,1],
 [0,0,0,0,0,0,1,1],
 [0,0,0,0,0,0,0,1]]

On the second day, add 5 walls to quarantine the viral region on the right. The virus is fully contained.

 

Example 2:

Input: grid = 
[[1,1,1],
 [1,0,1],
 [1,1,1]]
Output: 4
Explanation: Even though there is only one cell saved, there are 4 walls built.
Notice that walls are only built on the shared boundary of two different cells.

 

Example 3:

Input: grid = 
[[1,1,1,0,0,0,0,0,0],
 [1,0,1,0,1,1,1,1,1],
 [1,1,1,0,0,0,0,0,0]]
Output: 13
Explanation: The region on the left only builds two new walls.

 

Note:

  1. The number of rows and columns of grid will each be in the range [1, 50].
  2. Each grid[i][j] will be either 0 or 1.
  3. Throughout the described process, there is always a contiguous viral region that will infect strictly moreuncontaminated squares in the next round.

 

這道題給了我們一個由0和1組成的二維數組,其中0表示健康細胞,而1表示病毒細胞,多個相鄰的1組成了病毒細胞群,每天都會向周圍擴散一圈,除非我們在其跟健康細胞之間建立隔離牆,這樣其才會不會擴散。我們每天只能給一個病毒細胞群來建立隔離牆,其他的細胞群會進行擴散。問最終我們需要多少個隔離牆。這道題真的挺難,博主研究了好久才弄明白題目的意思。首先要明白一點,病毒細胞只會向上下左右四個方向相鄰的健康細胞擴散。需要注意的一點是,需要的隔離牆的數量可能大於周圍相鄰的健康細胞,最明顯的就是例子2中,只有一個健康細胞,但是需要四個隔離牆才能保護這個健康細胞不被感染。還有就是,我們需要隔離某個病毒細胞群的判定依據是其能感染的健康細胞的數量,而不是需要建的牆的數量或者病毒細胞的個數,這點很重要,博主之前沒有注意這一點,導致fail了一個test case。所以我們要做的就是要求出每個病毒細胞群能感染的健康細胞的數量,其周圍能建牆的地方,以及每個病毒細胞的位置。我們再其中選擇能感染最多健康細胞的病毒細胞群進行建牆,建完牆后,我們將該群中的所有病毒細胞標記為-1,跟其他細胞區分出來。對於其他所有的病毒細胞群,將其周圍能建牆的地方(即健康細胞)都標記為1,表示其現在已經被感染成了病毒細胞。然后再進行新的一輪循環檢測,直到無法找出新的病毒細胞為止。

我們先找值為1的點,找到后,以其作為起點,進行BFS遍歷,將和其相連的所有為1的點都找出來,在BFS遍歷的過程中,如果我們檢測到周圍位置值為0,將其加入walls數組,表示這里可以建隔離牆,如果檢測到周圍位置為1,將其加入virus數組,表示這里是病毒細胞,注意起始位置也要提前加入virus數組。我們這里為了節省維度,將二維的坐標都encode成了一個int數字。BFS遍歷結束后,我們根據walls數組來算出能感染的健康細胞的個數,因為我們前面提到過建隔離牆的位置可能大於健康細胞的個數,所以我們只要去除wall數組的重復項即可,利用HashSet的去重復項原理,然后將剩下的個數放入cells數組中。把cells,walls,和virus數組放入一個vector中,表示一個病毒細胞群的信息,再放入一個大數組all中,這樣我們收集了所有病毒細胞群的信息后,可以根據可感染的健康細胞個數由多到少來排序,這樣我們就把第一個病毒細胞群中所有virus數組的位置值變為-1,並且把可感染的健康細胞個數累加到結果res中。然后把后面所有的病毒細胞群中walls的位置值都變為1即可。當all數組為空時,跳出循環,表示沒有檢測到病毒細胞群或者全部都被感染了,參見代碼如下:

 

class Solution {
public:
    int containVirus(vector<vector<int>>& grid) {
        int res = 0, m = grid.size(), n = grid[0].size();
        vector<vector<int>> dirs{{-1,0},{0,1},{1,0},{0,-1}};
        while (true) {
            unordered_set<int> visited;
            vector<vector<vector<int>>> all;
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (grid[i][j] == 1 && !visited.count(i * n + j)) {
                        queue<int> q{{i * n + j}};
                        vector<int> virus{i * n + j};
                        vector<int> walls;
                        visited.insert(i * n + j);
                        while (!q.empty()) {
                            auto t = q.front(); q.pop();
                            for (auto dir : dirs) {
                                int x = (t / n) + dir[0], y = (t % n) + dir[1];
                                if (x < 0 || x >= m || y < 0 || y >= n || visited.count(x * n + y)) continue;
                                if (grid[x][y] == -1) continue;
                                else if (grid[x][y] == 0) walls.push_back(x * n + y);
                                else if (grid[x][y] == 1) {
                                    visited.insert(x * n + y);
                                    virus.push_back(x * n + y);
                                    q.push(x * n + y);
                                }
                            }
                        }
                        unordered_set<int> s(walls.begin(), walls.end());
                        vector<int> cells{(int)s.size()};
                        all.push_back({cells ,walls, virus});
                    }
                }
            }
            if (all.empty()) break;
            sort(all.begin(), all.end(), [](vector<vector<int>> &a, vector<vector<int>> &b) {return a[0][0] > b[0][0];});
            for (int i = 0; i < all.size(); ++i) {
                if (i == 0) {
                    vector<int> virus = all[0][2];
                    for (int idx : virus) grid[idx / n][idx % n] = -1;
                    res += all[0][1].size();
                } else {
                    vector<int> wall = all[i][1];
                    for (int idx : wall) grid[idx / n][idx % n] = 1;
                }
            }
        }
        return res;
    }
};

 

參考資料:

https://discuss.leetcode.com/topic/114208/c-dfs-12ms

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM