1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
// 方向数组
var dir [4][2]int = [4][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
func containVirus(grid [][]int) int {
/*
1. 获取最大的感染面积区域和所需的防火墙数目
2. 对最大感染面积区域的病毒进行阻断消杀
3. 存活的病毒进行扩散处理
4. 重复上述步骤,直到所需防火墙为0为止
*/
res := 0 // 最终需要的防火墙数目
r, c := len(grid), len(grid[0])
// 当前区域的防火墙临时数目
cur := 0
// 对当前区域的防火墙内的病毒进行阻断消杀
var toDead func(int, int)
// 对未隔离的病毒进行扩散
var spread func(int, int, [][]int)
// 对当前区域的扩散范围进行搜索并统计所需防火墙
var DFS func(int, int, int, [][]int) int
// 搜索一天内感染最大的区域所需要的防火墙数目
var getMaxAreaNeedWalls func() int
getMaxAreaNeedWalls = func() int {
/*
m: 最大的感染面积
cnt: 当前最大感染面积的区域所需的防火墙数目
x,y: 病毒区域
s: 表示当前区域要修建墙的状态,并且每个区域的s都是不一样的,互相不能影响 DFS完给s-1
*/
m, cnt, x, y, s := 0, 0, -1, -1, -3
vis := make([][]int, r) // 访问标记数组
for i := 0; i < r; i++ {
vis[i] = make([]int, c)
}
for i := 0; i < r; i++ {
for j := 0; j < c; j++ {
// 找到没有访问的病毒区域
if grid[i][j] == 1 && vis[i][j] != 1 {
//当前区域需要的防火墙数量
cur = 0
//当前区域能感染的面积
temp := DFS(i, j, s, vis)
if temp > m {
m = temp
cnt = cur
x, y = i, j
}
s-- // 区域状态数递减
}
}
}
// 没有病毒区域了只需0个防火墙
if x == -1 {
return 0
}
// 对当天最大病毒感染面积区域的病毒进行阻断消杀
toDead(x, y)
// 重置访问数组
vis = make([][]int, r)
for i := 0; i < r; i++ {
vis[i] = make([]int, c)
}
for i := 0; i < r; i++ {
for j := 0; j < c; j++ {
// 对剩余病毒区域进行扩散处理
if grid[i][j] == 1 && vis[i][j] != 1 {
spread(i, j, vis)
}
}
}
// 返回最大感染面积区域所需的防火墙数目
return cnt
}
toDead = func(x, y int) {
// 病毒消杀标记
grid[x][y] = -2
// 四处搜索
for i := 0; i < 4; i++ {
x_, y_ := x+dir[i][0], y+dir[i][1]
// 未越界且未访问且为病毒(状态转移)
if x_ >= 0 && x_ < r && y_ >= 0 && y_ < c && grid[x_][y_] == 1 {
toDead(x_, y_)
}
}
}
spread = func(x, y int, vis [][]int) {
// 访问标记
vis[x][y] = 1
// 四处搜索
for i := 0; i < 4; i++ {
x_, y_ := x+dir[i][0], y+dir[i][1]
// 未越界且未访问
if x_ >= 0 && x_ < r && y_ >= 0 && y_ < c && vis[x_][y_] != 1 {
if grid[x_][y_] == 0 { // 边界条件
grid[x_][y_] = 1
vis[x_][y_] = 1
} else if grid[x_][y_] == 1 { // 状态转移
spread(x_, y_, vis)
}
}
}
}
DFS = func(x, y, s int, vis [][]int) int {
// 当前病毒区域所感染面积
res := 0
// 访问标记
vis[x][y] = 1
// 四处搜索
for i := 0; i < 4; i++ {
x_, y_ := x+dir[i][0], y+dir[i][1]
if x_ >= 0 && x_ < r && y_ >= 0 && y_ < c && vis[x_][y_] != 1 {
// 未感染区域
if grid[x_][y_] == 0 {
cur++ // 防火墙数目递增
// 判断是否为该病毒区域访问过
if vis[x_][y_] != s {
res++
vis[x_][y_] = s
}
} else if grid[x_][y_] == 1 { // 感染区域(状态转移)
res += DFS(x_, y_, s, vis)
}
}
}
return res
}
for { // 每次大循环模拟一整天
walls := getMaxAreaNeedWalls()
if walls == 0 {
break
}
res += walls // 统计当天最大感染区域所需防火墙数目
}
return res
}
|