Leetcode 749. 隔离病毒 C++

Leetcode 749. 隔离病毒

题目

病毒扩散得很快,现在你的任务是尽可能地通过安装防火墙来隔离病毒。

假设世界由二维矩阵组成,0 表示该区域未感染病毒,而 1 表示该区域已感染病毒。可以在任意 2 个四方向相邻单元之间的共享边界上安装一个防火墙(并且只有一个防火墙)。

每天晚上,病毒会从被感染区域向相邻未感染区域扩散,除非被防火墙隔离。现由于资源有限,每天你只能安装一系列防火墙来隔离其中一个被病毒感染的区域(一个区域或连续的一片区域),且该感染区域对未感染区域的威胁最大且保证唯一。

你需要努力使得最后有部分区域不被病毒感染,如果可以成功,那么返回需要使用的防火墙个数; 如果无法实现,则返回在世界被病毒全部感染时已安装的防火墙个数。

测试样例

示例 1:

输入: 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]]
输出: 10
说明:
一共有两块被病毒感染的区域: 从左往右第一块需要 5 个防火墙,同时若该区域不隔离,晚上将感染 5 个未感染区域(即被威胁的未感染区域个数为 5);
第二块需要 4 个防火墙,同理被威胁的未感染区域个数是 4。因此,第一天先隔离左边的感染区域,经过一晚后,病毒传播后世界如下:
[[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]]
第二题,只剩下一块未隔离的被感染的连续区域,此时需要安装 5 个防火墙,且安装完毕后病毒隔离任务完成。

示例 2:

输入: grid = 
[[1,1,1],
 [1,0,1],
 [1,1,1]]
输出: 4
说明: 
此时只需要安装 4 面防火墙,就有一小区域可以幸存,不被病毒感染。
注意不需要在世界边界建立防火墙。

示例 3:

输入: 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]]
输出: 13
说明: 
在隔离右边感染区域后,隔离左边病毒区域只需要 2 个防火墙了。

说明:

  1. grid 的行数和列数范围是 [1, 50]。
  2. grid[i][j] 只包含 0 或 1 。
  3. 题目保证每次选取感染区域进行隔离时,一定存在唯一一个对未感染区域的威胁最大的区域。

题解

统计挡板数量即统计周围0的个数,
如果说旁边有已经安放的挡板,也是计算周围0的个数,简单说明一下原因:安放挡板的位置一定是紧挨着1,如果旁边不是0我们要安放挡板显然是没有必要的,因为旁边是1,但他们并没有视为一个感染区域,即这个1旁边已经有了挡板,不需要安放了。所以我们只需要统计0的个数就可以了。
简单话考虑,我们不妨把已经隔离的病毒从1改为-1,可以在下次考虑时不将其视为一个感染区域

总体思路:
统计每个感染区域所能感染的个数,将最大影响区域进行隔离,统计0个数(即挡板个数)的同时将其改为-1
判断是否终止,不终止,循环上一步。终止条件:无1或无0

//本题有点漏题,感觉可能会导致答案不唯一的情况
比如
1 1 1 0 0 0 0 0 1
1 0 1 0 0 0 0 1 1
1 1 1 0 0 0 0 0 0
此时如果先隔离左后隔离右,需要7+5 = 12
若先隔离右后隔离左,需要 5 + 3 = 8
且都是扩散感染了4个,本题应该没有考虑这种情况,我觉得如果要输出最少防火墙个数,应该结合贪心的思想,即在统计最大影响区域的同时就要记录所需挡板数量,选择尽可能少的用挡板且尽可能大的防止扩散感染的区域。
详细过程见代码

代码

class Solution {
public:
    int setWall(vector<vector<int>>& grid,int x,int y){     //安放防火墙,同时将隔离的病毒改为-1
        int cnt = 0,m = grid.size(),n = grid[0].size(),size;
        int dir[4][2] = {
            {-1,0},{0,1},{1,0},{0,-1}
        };
        queue<pair<int,int>> q;
        vector<vector<bool>> visit(m,vector<bool>(n,false));
        q.push(make_pair(x,y));
        visit[x][y] = true;
        while(!q.empty()){
            size = q.size();
            while(size--){
                pair<int,int> now = q.front();
                q.pop();
                grid[now.first][now.second] = -1;       //该病毒会被隔离,改为-1
                for(int i=0; i<4; i++){
                    if(now.first+dir[i][0]>=0 && now.first+dir[i][0]<m 
                    && now.second+dir[i][1]>=0 && now.second+dir[i][1]<n){
                        if(grid[now.first+dir[i][0]][now.second+dir[i][1]] == 0)    cnt++;      //需要安放1个防火墙
                        else if(grid[now.first+dir[i][0]][now.second+dir[i][1]]==1 
                        && !visit[now.first+dir[i][0]][now.second+dir[i][1]]){
                            q.push(make_pair(now.first+dir[i][0],now.second+dir[i][1]));
                            visit[now.first+dir[i][0]][now.second+dir[i][1]] = true;
                        }
                            
                    }
                }
            }
        }
        return cnt;
    }
    vector<int> maxInfluence(vector<vector<int>>& grid,int& maxCnt){        //计算每个病毒区域所能影响未感染区域,返回影响最大的一个病毒所在的区域坐标
        int m = grid.size(),n = grid[0].size();
        vector<int> place(2,0);
        vector<vector<bool>> visit(m,vector<bool>(n,false));
        maxCnt = 0;
        int dir[4][2] = {
            {-1,0},{0,1},{1,0},{0,-1}
        };
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                if(grid[i][j]==1 && !visit[i][j]){      //一个未访问的病毒区域,计算其影响的未感染区域
                    vector<vector<bool>> use(m,vector<bool>(n,false));
                    queue<pair<int,int>> q;
                    int size,cnt=0;
                    q.push(make_pair(i,j));
                    visit[i][j] = true;
                    while(!q.empty()){
                        size = q.size();
                        while(size--){
                            pair<int,int> now = q.front();
                            q.pop();
                            for(int k=0; k<4; k++){
                                if(now.first+dir[k][0]>=0 && now.first+dir[k][0]<m 
                                && now.second+dir[k][1]>=0 && now.second+dir[k][1]<n){
                                    if(grid[now.first+dir[k][0]][now.second+dir[k][1]] == 0 
                                    && !use[now.first+dir[k][0]][now.second+dir[k][1]]){
                                        cnt++;
                                        use[now.first+dir[k][0]][now.second+dir[k][1]] = true;      //该影响区域计算过,进行标记,避免重复计算
                                    }else if(grid[now.first+dir[k][0]][now.second+dir[k][1]]==1 
                                    && !visit[now.first+dir[k][0]][now.second+dir[k][1]]){
                                        q.push(make_pair(now.first+dir[k][0],now.second+dir[k][1]));
                                        visit[now.first+dir[k][0]][now.second+dir[k][1]] = true;
                                    }
                                }
                            }
                        }
                    }
                    if(cnt > maxCnt){
                        maxCnt = cnt;
                        place[0] = i;
                        place[1] = j;
                    }
                }
            }
        }
        return place;
    }

    void expandVirus(vector<vector<int>>& grid){        //病毒进行扩散
        int m = grid.size(),n = grid[0].size();
        vector<vector<bool>> visit(m,vector<bool>(n,false));
        int dir[4][2] = {
            {-1,0},{0,1},{1,0},{0,-1}
        };
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                if(grid[i][j]==1 && !visit[i][j]){
                    queue<pair<int,int>> q;
                    int size;
                    q.push(make_pair(i,j));
                    visit[i][j] = true;
                    while(!q.empty()){
                        size = q.size();
                        while(size--){
                            pair<int,int> now = q.front();
                            q.pop();
                            for(int k=0; k<4; k++){
                                if(now.first+dir[k][0]>=0 && now.first+dir[k][0]<m 
                                && now.second+dir[k][1]>=0 && now.second+dir[k][1]<n){
                                    if(grid[now.first+dir[k][0]][now.second+dir[k][1]] == 0){
                                        grid[now.first+dir[k][0]][now.second+dir[k][1]] = 1;
                                        visit[now.first+dir[k][0]][now.second+dir[k][1]] = true;
                                    }else if(grid[now.first+dir[k][0]][now.second+dir[k][1]]==1 
                                    && !visit[now.first+dir[k][0]][now.second+dir[k][1]]){
                                        q.push(make_pair(now.first+dir[k][0],now.second+dir[k][1]));
                                        visit[now.first+dir[k][0]][now.second+dir[k][1]] = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    int containVirus(vector<vector<int>>& grid) {
        int maxCnt = 0;
        int ans=0;
        do{
            vector<int> place = maxInfluence(grid,maxCnt);
            if(maxCnt == 0) break;
            //cout<<maxCnt<<" "<<place[0]<<" "<<place[1]<<endl;
            ans += setWall(grid,place[0],place[1]);
            expandVirus(grid);
        }while(1);
        
        return ans;
    }
};

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/contain-virus
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值