749-Contain Virus

Description:
A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls.

The world is modeled as a 2-D array of cells, where 0 represents uninfected cells, and 1 represents cells contaminated with the virus. A wall (and only one wall) can be installed between any two 4-directionally adjacent cells, on the shared boundary.

Every night, the virus spreads to all neighboring cells in all four directions unless blocked by a wall. Resources are limited. Each day, you can install walls around only one region – the affected area (continuous block of infected cells) that threatens the most uninfected cells the following night. There will never be a tie.

Can you save the day? If so, what is the number of walls required? If not, and the world becomes fully infected, return the number of walls used.


Example 1:

Input: 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]]
Output: 10
Explanation:
There are 2 contaminated regions.
On the first day, add 5 walls to quarantine the viral region on the left. The board after the virus spreads is:

[[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]]

On the second day, add 5 walls to quarantine the viral region on the right. The virus is fully contained.

Example 2:

Input: grid = 
[[1,1,1],
 [1,0,1],
 [1,1,1]]
Output: 4
Explanation: Even though there is only one cell saved, there are 4 walls built.
Notice that walls are only built on the shared boundary of two different cells.

Example 3:

Input: 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]]
Output: 13
Explanation: The region on the left only builds two new walls.

Note:
1.The number of rows and columns of grid will each be in the range [1, 50].
2.Each grid[i][j] will be either 0 or 1.
3.Throughout the described process, there is always a contiguous viral region that will infect strictly more uncontaminated squares in the next round.


问题描述:
给定一个二维数组grid,数组里的值为代表未被感染,1代表已被感染,感染的地方可以从4个方向传播(上,下,左,右),但是感染可以通过隔离墙挡住,而你的任务就是设立隔离墙阻止感染源的传播。然而问题是,材料有限,你每次只能隔离感染地带(在四个方向中相邻即为连接,而感染地带指的是连通分量,即一整块互相连接的感染地)中将会感染最多地区的那一个。
问题是,如果能阻止感染的传播,你需要返回使用的墙的数目,如果不能,你也要返回使用的墙的数目。


例子:

Input: 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]]

如图所示,有左右两个感染地带,左边可以传播5块地区,右边只能传播4块地区,因此先隔离左边那块,感染墙+5,之后,右边的感染区已经传播了4个地区,而新形成的感染地带需要5个隔离墙(千万不要把可以感染的数目可以隔离墙数目弄混了)。因此总计10个

我看了一下,leetcode上面这一题的解法都差不多(看起来都比较复杂),因此就上我的吧。


/*
*其实算法思路还是比较简单的。在递归连通区域(即感染地带)的时候,你需要获取3个信息:
1.该连通区域每个元素的下标(如果这块区域将要感染最多的地区,那么需要对该连通区域的元素进行处理)
2.该连通区域即将要感染的元素的下标(如果这块区域不是感染最多的地区,那么需要将这些元素设置为感染)
3.该连通区域需要的隔离墙的数目(如果该地区将要感染最多的地区,那么需要隔离墙数目需要加上这个)
整个算法就是每一轮,递归所有的连通区域(感染地带),获取以上三个信息,然后进行处理,直到所有地区
被感染或者病毒被成功隔离
我将grid中的元素分为了以下三种状态:
0.未被感染
1.已被感染
2.已被隔离
*/
class Solution {
    private int[][] dirs = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};
    private class Count{
        int value = 0;
        public Count(){

        }
        public void inc(){
             value++;
        }
    }
    public int containVirus(int[][] grid) {
        int m = grid.length, n = grid[0].length;

        int wallCount = 0;
        while(true){
            List<List<int[]>> regionList = new ArrayList();
            List<Count> countList = new ArrayList();
            List<List<int[]>> tList = new ArrayList();
            boolean[][] visited = new boolean[m][n];
            for(int i = 0;i < m;i++){
                for(int j = 0;j < n;j++){
                    if(!visited[i][j] && grid[i][j] == 1){
                        List<int[]> region = new ArrayList();
                        List<int[]> t = new ArrayList();
                        Count count = new Count();
                        visited[i][j] = true;
                        t.add(new int[]{i, j});
                        dfs(region, t, new boolean[m][n], count, grid, m, n, i, j, visited);
                        regionList.add(region);
                        tList.add(t);
                        countList.add(count);
                    }
                }
            }
            int index = -1;
            int maxSize = 0;
            for(int i = 0;i < regionList.size();i++){
                List<int[]> region = regionList.get(i);
                if(region.size() > maxSize){
                    maxSize = region.size();
                    index = i;
                }
            }
            if(index == -1) break;

            for(int i = 0;i < regionList.size();i++){
                if(i == index){
                    List<int[]> maxregion = regionList.get(i);
                    wallCount += countList.get(i).value;
                    List<int[]> t = tList.get(i);
                    for(int[] cell : t){
                        grid[cell[0]][cell[1]] = 2;
                    }
                }else{
                    List<int[]> region = regionList.get(i);
                    for(int[] cell : region){
                        grid[cell[0]][cell[1]] = 1;
                    }
                }
            }
        }

        return wallCount;
    }
    public void dfs(List<int[]> line,List<int[]> line1, boolean[][] tempvisited, Count count, int[][] grid, int m, int n, int i, int j, boolean[][] visited){
        for(int[] dir : dirs){
            int newi = i + dir[0], newj = j + dir[1];
            if(newi >= 0 && newi < m && newj >= 0 && newj < n){
                if(grid[newi][newj] == 0)   count.inc();
                if(!visited[newi][newj]){
                    if(!tempvisited[newi][newj] && grid[newi][newj] == 0){
                        tempvisited[newi][newj] = true;
                        line.add(new int[]{newi, newj});
                    }else if(grid[newi][newj] == 1){
                        visited[newi][newj] = true;
                        line1.add(new int[]{newi, newj});
                        dfs(line, line1, tempvisited, count, grid, m, n, newi, newj, visited);
                    }
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值