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:
- The number of rows and columns of
grid
will each be in the range[1, 50]
. - Each
grid[i][j]
will be either0
or1
. - Throughout the described process, there is always a contiguous viral region that will infect strictly more uncontaminated squares in the next round.
---------------------------------------------------------------------------------------------
算法本身不难,难点是对题目的理解。有几点需要理解清楚:
- 防火墙可以包围某个连通病毒区域,而不是要求防火墙是连通的
- 从0到1相当于1一次感染。针对一个连通区域,感染几次要几个防火墙,相当于代码里的edges。edges里是可以重复的,也就是从四面八方感染某一个cell。
- 防火墙个数可能多于新感染区域个数,题目的意思是按照新感染个数排序,也就是set(edges)
以下是代码:
from collections import Counter
class Solution:
def bfs(self, grid, x, y, seen):
pos, edge = [(x,y)], []
r, c = len(grid), len(grid[0])
layers = [{(x, y)}, set()]
seen.add((x,y)) #bug2
cur, nxt = 0, 1
while (layers[cur]):
for cx, cy in layers[cur]:
for (dx, dy) in [(1,0), (0,1), (-1,0), (0,-1)]: #bug1:(0,0)
nx, ny = cx + dx, cy + dy
if (nx >= 0 and nx < r and ny >= 0 and ny < c and (nx, ny) not in seen):
if (grid[nx][ny] == 0):
edge.append((nx, ny))
elif (grid[nx][ny] == 1):
seen.add((nx, ny))
pos.append((nx, ny))
layers[nxt].add((nx, ny))
layers[cur].clear()
cur, nxt = nxt, cur
return pos, edge
def get_virus(self, grid):
r, c = len(grid), len(grid[0])
vpos, edges = [], []
seen = set()
for i in range(r):
for j in range(c):
if (grid[i][j] == 1 and (i,j) not in seen):
pos, edge = self.bfs(grid, i, j, seen)
vpos.append(pos)
edges.append(edge)
return vpos, edges
def containVirus(self, grid):
vpos, edges = self.get_virus(grid)
res = 0
while (edges):
maxi, maxv = 0, 0 #bug3
for i in range(len(edges)):
cl = len(set(edges[i])) #按感染最多的cell算,不是按最长的墙算
if (cl > maxv):
maxi, maxv = i, len(set(edges[i]))
res += len(edges[maxi])
for (x, y) in vpos[maxi]:
grid[x][y] = 2
for i in range(len(edges)):
if (i != maxi):
for (x, y) in edges[i]:
grid[x][y] = 1
vpos, edges = self.get_virus(grid)
return res
s = Solution()
print(s.containVirus([[0,1,0,1,1,1,1,1,1,0],
[0,0,0,1,0,0,0,0,0,0],
[0,0,1,1,1,0,0,0,1,0],
[0,0,0,1,1,0,0,1,1,0],
[0,1,0,0,1,0,1,1,0,1],
[0,0,0,1,0,1,0,1,1,1],
[0,1,0,0,1,0,0,1,1,0],
[0,1,0,1,0,0,0,1,1,0],
[0,1,1,0,0,1,1,0,0,1],
[1,0,1,1,0,1,0,1,0,1]]))