749. 隔离病毒

题目:

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

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

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

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


示例 1:

输入: isInfected = [[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 个墙来隔离病毒区域。此时病毒已经被完全控制住了。


示例 2:

输入: isInfected = [[1,1,1],[1,0,1],[1,1,1]]
输出: 4
解释: 虽然只保存了一个小区域,但却有四面墙。
注意,防火墙只建立在两个不同区域的共享边界上。


示例 3:

输入: isInfected = [[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 个防火墙。


提示:

m == isInfected.length
n == isInfected[i].length
1 <= m, n <= 50
isInfected[i][j] is either 0 or 1
在整个描述的过程中,总有一个相邻的病毒区域,它将在下一轮 严格地感染更多未受污染的方块


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


思路:

思路简单来说就是一个循环:
遍历整个grid寻找所有未被访问的病毒点->计算该病毒点以及邻接的病毒点威胁的区域大小,从中找到最大区域->最大区域建墙,其他区域扩展
当最大威胁区域为0时,说明整个二维世界被感染或者病毒都已经被隔离了,结束循环即可。


代码:

int row=0,col=0;
const int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
class Solution {
public:int containVirus(vector<vector<int>>& grid) {int res=0,cnt=0;int x=0,y=0;row=grid.size(),col=grid[0].size();//table是记录grid中所有的病毒块(相邻的病毒看成一个病毒块)的list结构,其中第一个元素是危险区域(威胁最大)的起始位置list<pair<int,int>> table;int vis[51][51];//check的返回值是危险区域需要建墙数while((cnt=check(table,grid))!=0){res+=cnt;memset(vis,0,sizeof(vis));auto [x,y]=table.front();table.pop_front();//第一个是要加防火墙的块,expand值val,设置为-1,表示将该病毒区域设置为-1,表示已经被隔离,而且-1值在下次check时不会              //再次被检查,剪枝expand(x,y,-1,vis,grid);//其他的病毒区域会扩展,val设为1,表示与病毒相邻的区域会变成1for(auto [x,y]:table){expand(x,y,1,vis,grid);}}return res;}//遍历整个grid,从中找出所有的病毒区域放到table中,并且找到威胁最大的区域放到table的第一个元素中,返回危险病毒块威胁的区域       //需要建墙数int check(list<pair<int,int>>&table,vector<vector<int>>&grid){bool flag=false;int wall=0;int vis[51][51];memset(vis,0,sizeof(vis));for(int i=0;i<row;i++){for(int j=0;j<col;j++){if(grid[i][j]==1){//vis记录已经被访问过的病毒,也即一个病毒块只会被dfs函数处理一次if(vis[i][j]==false){vis[i][j]=true;//cnt是当前病毒块威胁的区域的大小int cnt=dfs(i,j,vis,grid);//跟新当前威胁区域的最大值if(cnt>wall){wall=cnt;//需要将之前的威胁最大的病毒块首地址从第一个取出,放到最后if(table.empty()!=true){auto front=table.front();table.pop_front();table.push_back(front);}//当前最大值放到list的首位table.push_front(make_pair(i,j));}//如果不是最大值,而且该区域可以传播(威胁的区域大于0),放到list的尾部else if(cnt!=0){table.push_back(make_pair(i,j));}                       }}}}//list为空,说明所有的病毒区域都不能再扩展(所有病毒被隔离,或者都被感染了)模拟过程完成if(table.empty()==true){return 0;}else{memset(vis,0,sizeof(vis));vis[table.front().first][table.front().second]=true;//计算危险病毒块需要建墙数return cnt(table.front().first,table.front().second,vis,grid);}}//计算病毒区域需要建墙数int cnt(int x,int y,int vis[51][51],vector<vector<int>>&grid){int res=0;for(int i=0;i<4;i++){int nx=x+dir[i][0],ny=y+dir[i][1];if(nx<row&&nx>=0&&ny<col&&ny>=0&&vis[nx][ny]==false){if(grid[nx][ny]==0){//发现一个可被感染的区域,用-1标记,防止重复计算,同时要记录位置,本次循环结束要恢复为0res++;}if(grid[nx][ny]==1){vis[nx][ny]=true;//递归计算下一个病毒需要建墙数res+=cnt(nx,ny,vis,grid);                  }}}return res;        }int dfs(int x,int y,int vis[51][51],vector<vector<int>>&grid){int res=0;vector<pair<int,int>> recover;vector<pair<int,int>> deepin;for(int i=0;i<4;i++){int nx=x+dir[i][0],ny=y+dir[i][1];if(nx<row&&nx>=0&&ny<col&&ny>=0&&vis[nx][ny]==false){if(grid[nx][ny]==0){//发现一个可被感染的区域,vis设置为1标记,防止重复计算,同时要记录位置,本次循环结束要恢复为0vis[nx][ny]=true;recover.push_back(make_pair(nx,ny));res++;}//以为一个健康区域可能被若干个病毒威胁,为避免重复计算,现将当前病毒威胁区域的vis都设置为0,再递归遍历下一个//病毒区域,所以访问当前位置的邻接的区域中的健康区域要在访问病毒区域之后,所以要线记录病毒区域。if(grid[nx][ny]==1){vis[nx][ny]=true;deepin.push_back(make_pair(nx,ny));                   }}}//递归计算当位置的邻接位置中的病毒区域for(auto [x,y]:deepin){res+=dfs(x,y,vis,grid);}//恢复原来的健康区域(因为这个vis在check中是通用的,一个病毒块的威胁区域和另一个是不相关的,所以要恢复)for(auto [x,y]:recover){vis[x][y]=false;}return res;}//病毒扩展,建防火墙的函数(病毒扩展时val为1,将邻接节点变为1,建墙时设置病毒区域为-1,其他不变)void expand(int x,int y,int val,int vis[51][51],vector<vector<int>>&grid){//如果设置了防火墙之后,原先的病毒设置为-1,防止下次check时再进行检查  grid[x][y]=val;       for(int i=0;i<4;i++){int nx=x+dir[i][0],ny=y+dir[i][1];if(nx>=0&&nx<row&&ny>=0&&ny<col&&vis[nx][ny]==false){ //如果当前区域是健康的,而且当前是扩展过程,则将其设置为1,表示变为病毒区域if(grid[nx][ny]==0&&val==1){grid[nx][ny]=1;//设置为true为了防止扩展的区域被二次扩展,即被当做之前的病毒区域再被扩展,vis[nx][ny]=true;}//如果当前位置是病毒,如果是扩展过程,设置为1(保持原值),建墙过程,设置为-1,表示已被控制,不可再扩展else if(grid[nx][ny]==1){vis[nx][ny]=true;                   expand(nx,ny,val,vis,grid);}}}}
};

入门力扣自学笔记96 C++ (题目编号749)相关推荐

  1. 入门力扣自学笔记118 C++ (题目编号1413)

    1413. 逐步求和得到正数的最小值 题目: 给你一个整数数组 nums .你可以选定任意的 正数 startValue 作为初始值. 你需要从左到右遍历 nums 数组,并将 startValue ...

  2. 入门力扣自学笔记52 C++ (题目编号929)

    929. 独特的电子邮件地址 题目: 每个 有效电子邮件地址 都由一个 本地名 和一个 域名 组成,以 '@' 符号分隔.除小写字母之外,电子邮件地址还可以含有一个或多个 '.' 或 '+' . 例如 ...

  3. 入门力扣自学笔记150 C++ (题目编号670)

    670. 最大交换 题目: 给定一个非负整数,你至多可以交换一次数字中的任意两位.返回你能得到的最大值. 示例 1 : 输入: 2736 输出: 7236 解释: 交换数字2和数字7. 示例 2 : ...

  4. 20210325:力扣递归,回溯类型题目合集

    力扣递归,回溯类型题目合集 题目 思路与算法 代码实现 写在最后 题目 子集 2. 90. 子集 II 3. 40. 组合总和 II 4. 22. 括号生成 思路与算法 子集:注释的很详细,递归生成子 ...

  5. 力扣题目归类,顺序刷题不再难

    目录 介绍 前奏-基础篇 中篇-链表.树的相关操作 进阶-回溯.动态规划 脑筋急转弯 介绍 大家好,相信很多人都知道刷力扣的重要性,但是如果不能将题目很好的归类整理专一练习,而是东做一道西做一道,那么 ...

  6. 力扣数据库题目刷题日记

    一个准备秋招的菜鸟 此前已经在力扣上面刷过一些题目,从今天开始记录刷题 1. Day1 96/97题 难度:中等 解题思路 首先需要读懂题目的意思,必须要保证容量大于相同分数的人数的同时,选择最低的分 ...

  7. 力扣刷题记录-回溯算法相关题目

    首先介绍一下回溯算法 回溯通常在递归函数中体现,本质也是一种暴力的搜索方法,但可以解决一些用for循环暴力解决不了的问题,其应用有: 1.组合问题: 例:1 2 3 4这些数中找出组合为2的组合,有1 ...

  8. 教你创建电脑、手机同步的markdown云笔记--力扣刷题力荐!

    开篇先致歉 其他不谈,开篇必须先给各位读者道个歉,年后工作上比较忙,加上最近闲暇的时间都用来在力扣上刷算法题了,导致公众号断更有些严重啊.再加上年后将健身减重提上了日程,时间上就更显的捉襟见肘了. 不 ...

  9. 力扣- -正则表达式匹配

    力扣- -正则表达式匹配 文章目录 力扣- -正则表达式匹配 一.题目描述 二.分析 方法一:Dp函数 明确状态和选择 确定状态转译方程 确定base case 完整代码 方法二:Dp table 明 ...

  10. 力扣--- 滑动谜题

    力扣- 滑动谜题 文章目录 力扣--- 滑动谜题 一.题目描述 二.问题分析 三.代码 一.题目描述 二.问题分析 对于这种计算 最小步数的问题,我们就要敏感地想到 BFS 算法. 这个题目转化成 B ...

最新文章

  1. SpringMvc多语言配置
  2. 美国罪案故事第一季/全集American Crime Story迅雷下载
  3. Launch debug in SWI1 workflow
  4. Flash Builder4.6 破解方法的实践
  5. java io操作压缩文件_Java操作zip-压缩和解压文件
  6. 指针07:指针和函数
  7. 29.TCP/IP 详解卷1 --- 网络文件系统
  8. android fastboot 最新版,用adb、fastboot拯救你的安卓手机
  9. html读取在线文件,javascript中如何读取文件?
  10. python virtualenv_python之virtualenv的简单使用方法(必看篇)
  11. 中文论文检索证明怎么开_作者如何拿到论文检索证明
  12. Linux高清壁纸软件,十个小众的 Linux 桌面软件
  13. 私域流量客服社群运营员工工作绩效表格方案计划手册指南宝典
  14. flv是什么视频格式?怎么把flv转换成mp4?
  15. 从多个Word文档中批量取值,整理到Excel表中。
  16. 谷歌colab运行自己的项目的一些细节
  17. windows配置mysql8.0主从数据库,主从数据同步。
  18. DM8 数据守护(Data Watch)搭建
  19. 游戏必备组件_一款Beta版游戏周销量 30 万份,独立游戏究竟有多火?
  20. 详解:传奇手游代理平台需要多少

热门文章

  1. 【色空win7动漫美女诱惑主题】
  2. 计算机及其工作原理ppt,计算机及其工作原理ppt课件
  3. android 最新adt下载地址,Android SDK和最新ADT下载地址
  4. CuteFtpnbsp;Pro之站点导入导出
  5. 免费小说网站源码 主题XSnov WordPress主题
  6. 最新PHP超精简全站自适应小说网网站源码
  7. 社会工程学攻击的三个典例
  8. 鼎捷易助8.0ERP系统制造业ERP系统介绍
  9. oracle net Manager 配置连接 tiptop 鼎捷ERP 数据库
  10. S.O. 推出程序员身价计算器,看看自己值多少钱?