public: intencode(const vector<vector<int>>& mat, int m, int n){ int x = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { x = x * 2 + mat[i][j]; } } return x; }
vector<vector<int>> decode(int x, int m, int n) { vector<vector<int>> mat(m, vector<int>(n)); for (int i = m - 1; i >= 0; --i) { for (int j = n - 1; j >= 0; --j) { mat[i][j] = x & 1; x >>= 1; } } return mat; }
voidconvert(vector<vector<int>>& mat, int m, int n, int i, int j){ for (int k = 0; k < 5; ++k) { int i0 = i + dirs[k][0], j0 = j + dirs[k][1]; if (i0 >= 0 && i0 < m && j0 >= 0 && j0 < n) { mat[i0][j0] ^= 1; } } }
intminFlips(vector<vector<int>>& mat){ int m = mat.size(), n = mat[0].size(); int x_start = encode(mat, m, n), step = 0; if (x_start == 0) { return step; }
while (!q.empty()) { ++step; int k = q.size(); for (int _ = 0; _ < k; ++_) { vector<vector<int>> status = decode(q.front(), m, n); q.pop(); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { convert(status, m, n, i, j); int x_cur = encode(status, m, n); if (x_cur == 0) { return step; } if (!visited.count(x_cur)) { visited.insert(x_cur); q.push(x_cur); } convert(status, m, n, i, j); } } } }
classSolution: defencode(self, mat, m, n): x = 0 for i inrange(m): for j inrange(n): x = x * 2 + mat[i][j] return x
defdecode(self, x, m, n): mat = [[0] * n for _ inrange(m)] for i inrange(m - 1, -1, -1): for j inrange(n - 1, -1, -1): mat[i][j] = x & 1 x >>= 1 return mat
defconvert(self, mat, m, n, i, j): for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1), (0, 0)]: i0, j0 = i + di, j + dj if0 <= i0 < m and0 <= j0 < n: mat[i0][j0] ^= 1
defminFlips(self, mat: List[List[int]]) -> int: m, n = len(mat), len(mat[0]) x_start, step = self.encode(mat, m, n), 0 if x_start == 0: return step
whilenot q.empty(): step += 1 k = q.qsize() for _ inrange(k): status = self.decode(q.get_nowait(), m, n) for i inrange(m): for j inrange(n): self.convert(status, m, n, i, j) x_cur = self.encode(status, m, n) if x_cur == 0: return step if x_cur notin visited: visited.add(x_cur) q.put_nowait(x_cur) self.convert(status, m, n, i, j)
假设二维矩阵 mat 经过 k 次翻转操作 T1, T2, ..., Tk 后变成全零矩阵,且 k 是最少的翻转次数,那么我们可以发现如下两个性质:
顺序无关性: 将这 k 次翻转操作任意打乱顺序,再从二维矩阵 mat 开始依次进行这些翻转操作,最后仍然会得到全零矩阵。证明如下:对于 mat 中的任意位置 (x, y),假设 T1, T2, ..., Tk 中有 c 次翻转操作会将其进行翻转,那么无论操作的顺序怎么被打乱,位置 (x, y) 被翻转的次数总是为 c 次,即位置 (x, y) 的最终状态不会受到操作顺序的影响。
翻转唯一性: 这 k 次翻转操作中,不会有两次翻转操作选择了相同的位置。证明方法类似:对于 mat 中的任意位置 (x, y),假设 T1, T2, ..., Tk 中有 c 次翻转操作会将其进行翻转,如果有两次翻转操作选择了相同的位置,那么将它们一起移除后,位置 (x, y) 要么被翻转 c 次,要么被翻转 c - 2 次。而减少一个位置 2 次翻转次数,对该位置不会有任何影响,即位置 (x, y) 的最终状态不会受到移除这两次翻转操作的影响。这样我们只使用 k - 2 次翻转操作,就可以得到全零矩阵,与 k 是最少的翻转次数矛盾。
根据上面两个结论,我们可以发现:对于二维矩阵 mat,如果我们希望它通过最少的翻转操作得到全零矩阵,那么 mat 中每个位置至多被翻转一次,并且翻转的顺序不会影响最终的结果。这样以来,翻转的方法一共只有 2^{MN 种,即对于 mat 中的每个位置,可以选择翻转或不翻转 2 种情况,位置的数量为 MN。
因此我们可以使用深度优先搜索来枚举所有的翻转方法。我们按照行优先的顺序搜索二维矩阵 mat 中的每个位置,对于当前位置,我们可以选择翻转或不翻转。当搜索完 mat 的所有位置时,如果 mat 变成了全零矩阵,那么我们就找到了一种满足要求的翻转方法。在所有满足要求的方法中,操作次数最少的即为答案。
voidconvert(vector<vector<int>>& mat, int m, int n, int i, int j){ for (int k = 0; k < 5; ++k) { int i0 = i + dirs[k][0], j0 = j + dirs[k][1]; if (i0 >= 0 && i0 < m && j0 >= 0 && j0 < n) { mat[i0][j0] ^= 1; } } }
voiddfs(vector<vector<int>>& mat, int m, int n, int pos, int flip_cnt){ if (pos == m * n) { bool flag = true; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (mat[i][j] != 0) { flag = false; } } } if (flag) { ans = min(ans, flip_cnt); } return; }
int x = pos / n, y = pos % n; // not flip dfs(mat, m, n, pos + 1, flip_cnt); // flip convert(mat, m, n, x, y); dfs(mat, m, n, pos + 1, flip_cnt + 1); convert(mat, m, n, x, y); }
intminFlips(vector<vector<int>>& mat){ int m = mat.size(), n = mat[0].size(); dfs(mat, m, n, 0, 0); return (ans != 1e9 ? ans : -1); } };
defconvert(self, mat, m, n, i, j): for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1), (0, 0)]: i0, j0 = i + di, j + dj if0 <= i0 < m and0 <= j0 < n: mat[i0][j0] ^= 1
defdfs(self, mat, m, n, pos, flip_cnt): if pos == m * n: ifall(mat[i][j] == 0for i inrange(m) for j inrange(n)): self.ans = min(self.ans, flip_cnt) return
x, y = pos // n, pos % n # not flip self.dfs(mat, m, n, pos + 1, flip_cnt) # flip self.convert(mat, m, n, x, y) self.dfs(mat, m, n, pos + 1, flip_cnt + 1) self.convert(mat, m, n, x, y)
defminFlips(self, mat: List[List[int]]) -> int: m, n = len(mat), len(mat[0]) self.dfs(mat, m, n, 0, 0) return self.ans if self.ans != 10**9else -1
voidconvert(vector<vector<int>>& mat, int m, int n, int i, int j){ for (int k = 0; k < 5; ++k) { int i0 = i + dirs[k][0], j0 = j + dirs[k][1]; if (i0 >= 0 && i0 < m && j0 >= 0 && j0 < n) { mat[i0][j0] ^= 1; } } }
voiddfs(vector<vector<int>>& mat, int m, int n, int pos, int flip_cnt){ if (pos == m * n) { bool flag = true; for (int j = 0; j < n; ++j) { if (mat[m - 1][j] != 0) { flag = false; break; } } if (flag) { ans = min(ans, flip_cnt); } return; }
int x = pos / n, y = pos % n; if (x == 0) { // in the first line we can choose either flip or not flip // not flip dfs(mat, m, n, pos + 1, flip_cnt); // flip convert(mat, m, n, x, y); dfs(mat, m, n, pos + 1, flip_cnt + 1); convert(mat, m, n, x, y); } else { // otherwise it depends on the upper grid if (mat[x - 1][y] == 0) { dfs(mat, m, n, pos + 1, flip_cnt); } else { convert(mat, m, n, x, y); dfs(mat, m, n, pos + 1, flip_cnt + 1); convert(mat, m, n, x, y); } } }
intminFlips(vector<vector<int>>& mat){ int m = mat.size(), n = mat[0].size(); dfs(mat, m, n, 0, 0); return (ans != 1e9 ? ans : -1); } };
defconvert(self, mat, m, n, i, j): for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1), (0, 0)]: i0, j0 = i + di, j + dj if0 <= i0 < m and0 <= j0 < n: mat[i0][j0] ^= 1
defdfs(self, mat, m, n, pos, flip_cnt): if pos == m * n: ifall(mat[m - 1][j] == 0for j inrange(n)): self.ans = min(self.ans, flip_cnt) return
x, y = pos // n, pos % n if x == 0: # in the first line we can choose either flip or not flip # not flip self.dfs(mat, m, n, pos + 1, flip_cnt) # flip self.convert(mat, m, n, x, y) self.dfs(mat, m, n, pos + 1, flip_cnt + 1) self.convert(mat, m, n, x, y) else: # otherwise it depends on the upper grid if mat[x - 1][y] == 0: self.dfs(mat, m, n, pos + 1, flip_cnt) else: self.convert(mat, m, n, x, y) self.dfs(mat, m, n, pos + 1, flip_cnt + 1) self.convert(mat, m, n, x, y)
defminFlips(self, mat: List[List[int]]) -> int: m, n = len(mat), len(mat[0]) self.dfs(mat, m, n, 0, 0) return self.ans if self.ans != 10**9else -1
public: voidconvert(vector<vector<int>>& mat, int m, int n, int i, int j){ for (int k = 0; k < 5; ++k) { int i0 = i + dirs[k][0], j0 = j + dirs[k][1]; if (i0 >= 0 && i0 < m && j0 >= 0 && j0 < n) { mat[i0][j0] ^= 1; } } }
intminFlips(vector<vector<int>>& mat){ int m = mat.size(), n = mat[0].size(); int ans = 1e9; for (int bin = 0; bin < (1 << n); ++bin) { vector<vector<int>> mat_copy = mat; int flip_cnt = 0; for (int j = 0; j < n; ++j) { if (bin & (1 << j)) { ++flip_cnt; convert(mat_copy, m, n, 0, j); } }
for (int i = 1; i < m; ++i) { for (int j = 0; j < n; ++j) { if (mat_copy[i - 1][j] == 1) { ++flip_cnt; convert(mat_copy, m, n, i, j); } } }
bool flag = true; for (int j = 0; j < n; ++j) { if (mat_copy[m - 1][j] != 0) { flag = false; break; } } if (flag) { ans = min(ans, flip_cnt); } } return (ans != 1e9 ? ans : -1); } };
classSolution: defconvert(self, mat, m, n, i, j): for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1), (0, 0)]: i0, j0 = i + di, j + dj if0 <= i0 < m and0 <= j0 < n: mat[i0][j0] ^= 1
defminFlips(self, mat: List[List[int]]) -> int: m, n = len(mat), len(mat[0]) ans = 1e9 for binary inrange(0, 1 << n): mat_copy = [line[:] for line in mat] flip_cnt = 0 for j inrange(n): if binary & (1 << j): flip_cnt += 1 self.convert(mat_copy, m, n, 0, j)
for i inrange(1, m): for j inrange(n): if mat_copy[i - 1][j] == 1: flip_cnt += 1 self.convert(mat_copy, m, n, i, j)
ifall(mat_copy[m - 1][j] == 0for j inrange(n)): ans = min(ans, flip_cnt) return ans if ans != 10**9else -1