16、隔离病毒

博客围绕二维矩阵中病毒隔离问题展开,矩阵中 0 表示未感染、1 表示已感染。每天只能隔离一个威胁最大的感染区域,需计算所需防火墙个数。给出多个示例,如不同输入矩阵对应的输出结果及说明,还提及代码编写耗时两小时。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

假设世界由二维矩阵组成,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);
			}
			
		}
	}
	
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值