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 个防火墙了。
说明:
- grid 的行数和列数范围是 [1, 50]。
- grid[i][j] 只包含 0 或 1 。
- 题目保证每次选取感染区域进行隔离时,一定存在唯一一个对未感染区域的威胁最大的区域。
题解
统计挡板数量即统计周围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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。