题目描述:
病毒扩散得很快,现在你的任务是尽可能地通过安装防火墙来隔离病毒。
假设世界由二维矩阵组成,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 。
题目保证每次选取感染区域进行隔离时,一定存在唯一一个对未感染区域的威胁最大的区域。
我的代码:
两个小时吧
class Solution {
// 假如已经被防火墙给阻断的病毒,我们假设变成了零
int result = 0;
public int containVirus(int[][] grid) {
while (!isend(grid)) {
int tem[] = getmax(grid);
int x = tem[0];
int y = tem[1];
// 计算所用的数量
boolean visi[][] = new boolean[grid.length][grid[0].length];
getnum(grid, x, y, visi);
// 一部分用防火墙隔离,将1变成0
fanghuoqiang(grid, x, y);
// 进行扩散
kuosan(grid);
}
return result;
}
public void getnum(int [][]grid,int x,int y,boolean isvi[][]){
if(isva(grid, x, y) && grid[x][y] == 1 && !isvi[x][y]){
isvi[x][y] = true;
getnum(grid, x + 1, y, isvi);
getnum(grid, x - 1, y, isvi);
getnum(grid, x, y + 1, isvi);
getnum(grid, x, y - 1, isvi);
}
if(isva(grid, x, y) && grid[x][y] == 0){
result ++;
}
}
public void kuosan(int [][] grid){
int direx [] = {0,0,-1,1};
int direy [] = {1,-1,0,0};
boolean visited[][] = new boolean[grid.length][grid[0].length];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if(grid[i][j] == 1 && !visited[i][j]){
visited[i][j] = true;
// 四个方向
for (int zuobiao = 0; zuobiao < 4; zuobiao++) {
int temx = i + direx[zuobiao];
int temy = j + direy[zuobiao];
if(isva(grid, temx, temy) && grid[temx][temy] == 0){
grid[temx][temy] = 1;
visited[temx][temy] = true;
}
}
}
}
}
}
public boolean isva(int [][] grid,int x,int y){
if(x < 0 || x >= grid.length || y < 0 || y >= grid[0].length){
return false;
}
return true;
}
// 判断是否应该停止
public boolean isend(int [][] grid){
for (int[] is : grid) {
for (int i : is) {
if(i == 1){
return false;
}
}
}
return true;
}
// 找到感染最多的那个区域的横纵坐标返回
int temmax = 0;
public int[] getmax(int grid[][]){
int max = 0;
boolean visited[][] = new boolean[grid.length][grid[0].length];
int tem[] = new int [2];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
temmax = 0;
if(grid[i][j] == 1 && !visited[i][j]){
// 针对0是否重复访问的情况
boolean temvisited[][] = new boolean[grid.length][grid[0].length];
dfs(i, j, grid, visited, temvisited);
if(max <= temmax){
这里一定要是小于等于,因为到最后可能都有防火墙,就会出现死循环了
max = temmax;
tem[0] = i;
tem[1] = j;
}
}
}
}
return tem;
}
public void fanghuoqiang(int [][]grid,int x,int y){
// 把能够阻挡的部分变成0方便操作
if(isva(grid, x, y) && grid[x][y] == 1){
grid[x][y] = 2;
fanghuoqiang(grid, x - 1, y);
fanghuoqiang(grid, x + 1, y);
fanghuoqiang(grid, x, y + 1);
fanghuoqiang(grid, x, y - 1);
}
}
public void dfs(int x,int y,int [][]grid,boolean visited[][],boolean temvisited[][]){
if(isva(grid, x, y)){
if(grid[x][y] == 0 && ! temvisited[x][y]){
temmax ++;
temvisited[x][y] = true;
return ;
}
if(grid[x][y] == 1 && !temvisited[x][y]){
temvisited[x][y] = true;
visited[x][y] = true;
dfs(x + 1, y, grid, visited, temvisited);
dfs(x - 1, y, grid, visited, temvisited);
dfs(x, y + 1, grid, visited, temvisited);
dfs(x, y - 1, grid, visited, temvisited);
}
}
}
}