📅  最后修改于: 2023-12-03 15:27:41.513000             🧑  作者: Mango
给定一个 $m\times n$ 的二进制矩阵,你可以将其中的一个位置从 0 变成 1 也可以将其中的一个位置从 1 变成 0。每做一次操作,可以将周围4个位置(上下左右)也一同变换。你需要在翻转最多 K 次之后,使得矩阵中的 1 的个数最多。
本道题最先想到的是通过二分答案 $r$。那么问题就转化成了:是否存在一种方案,可以将矩阵中的所有 0,都变成了 1,且最多翻转 $r$ 次(这里翻转 $x$ 次表示最多翻转 $x$ 次)?
对于判断答案是否可行,可以通过 DFS 遍历矩阵,将一个位置从 0 变成 1 或从 1 变成 0。由于每次需要一起翻转周围 4 个位置,因此可以利用 bfs 遍历这 4 个位置进行翻转。最终将矩阵中的 0 全部变成 1 后,与 $r$ 进行比较。如果 $r$ 小于等于已经翻转的次数,说明当前答案可行。
当 $r$ 大于可行的答案时,二分 $r$ 值:如果不存在一种方案,可以将所有 0 转换成 1,需要翻转的次数小于 $mid$,则更新答案,并将 $r$ 下界更新为 $mid+1$;否则将上界更新为 $mid-1$。
时间复杂度为 $O(\log C \times n^2)$,其中 $C$ 为矩阵中的 0 的数量。
当数字范围较小时,可以尝试使用位运算进行解决。我们可以枚举一个数 $s$,其中 $s$ 的二进制表示中不超过 $k$ 个位置为 1,表示翻转这些位置以后的操作可以将 0 变成 1。
对于每一种翻转方案 $s$,可以通过贪心的方式考虑最终翻转的位置。每次将所有可以翻转的位置按照当前方案 $s$ 的二进制表示中的位置进行排序,从最大的位置开始翻转。如果每次翻转完之后,1 的数量仍然增加,则说明这种方案可行。
时间复杂度为 $O(2^n\times n^2\times \log n)$,其中 $n$ 表示矩阵的长度。
from collections import deque
class Solution:
def maxCount(self, mat: List[List[int]], k: int) -> int:
m, n = len(mat), len(mat[0])
def dfs(i, j, visited, cnt):
if i < 0 or i >= m or j < 0 or j >= n or visited[i][j] or cnt > k:
return 0
visited[i][j] = True
res = 0
for dx, dy in [[1, 0], [-1, 0], [0, 1], [0, -1]]:
x, y = i+dx, j+dy
if 0 <= x < m and 0 <= y < n:
res += dfs(x, y, visited, cnt+mat[x][y]^1)
visited[i][j] = False
return res + mat[i][j]
l, r, ans = 0, m*n, 0
while l <= r:
mid = (l + r) // 2
flag = False
for i in range(m):
for j in range(n):
cnt = dfs(i, j, [[False for _ in range(n)] for _ in range(m)], 0)
if cnt <= mid:
ans = max(ans, cnt + sum([mat[x][y]^1 for x in range(m) for y in range(n)]))
flag = True
if flag:
l = mid + 1
else:
r = mid - 1
return ans
class Solution:
def maxCount(self, mat: List[List[int]], k: int) -> int:
m, n = len(mat), len(mat[0])
ans = 0
for s in range(1 << n):
if bin(s).count('1') > k:
continue
cur = [mat[i].copy() for i in range(m)]
for j in range(n):
if (1 << n-1-j) & s:
for i in range(m):
cur[i][j] ^= 1
cnt = sum([cur[i].count(1) for i in range(m)])
for j in range(n):
cc = sum([cur[i][j] for i in range(m)])
if cc < m - cc:
cnt += m-2*cc
ans = max(ans, cnt)
return ans