小O的矩阵变换
[题目链接](https://www.nowcoder.com/practice/b1c40c55c4724f75a659915c6700e5ce)
思路
给定两个 的 01 矩阵
和
,每次操作可以选择
的某一行或某一列,将该行/列所有元素翻转(0 变 1,1 变 0)。求最少操作次数使
变为
,若不可能输出 -1。
建模
设 表示第
行是否被翻转,
表示第
列是否被翻转(翻转偶数次等价于不翻转,所以每行/列只需考虑翻转 0 或 1 次)。
对于每个位置 ,翻转后的值为
,要求等于
,即:
$$
令 ,问题变为:能否找到
,使得对所有
满足
。
枚举固定 
整个方程组由 个未知数(
和
)组成。只要确定
的值(0 或 1),其余变量均可唯一确定:
- 由第 0 行约束:
,确定所有
;
- 由第
列第 0 列约束:
,确定所有
。
确定所有变量后,遍历全矩阵验证 是否对所有位置成立。若成立,操作次数为
。
对 和
分别尝试,取两者中满足条件的最小操作数;若两者均不满足,输出 -1。
样例演示
第一组():
$$
取 :
,
,
。
验证:,
,
,全部通过。
操作次数 。
取 同理得操作次数也为 2。答案为 2。
复杂度
- 时间复杂度:
,每组数据枚举两个
值,每次
验证。
- 空间复杂度:
。
代码
[sol-C++]
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<vector<int>> A(n, vector<int>(n)), B(n, vector<int>(n));
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> A[i][j];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> B[i][j];
vector<int> r(n), c(n);
int ans = INT_MAX;
for (int r0 = 0; r0 <= 1; r0++) {
r[0] = r0;
for (int j = 0; j < n; j++)
c[j] = (A[0][j] ^ B[0][j]) ^ r[0];
for (int i = 1; i < n; i++)
r[i] = (A[i][0] ^ B[i][0]) ^ c[0];
bool ok = true;
for (int i = 0; i < n && ok; i++)
for (int j = 0; j < n && ok; j++)
if ((r[i] ^ c[j]) != (A[i][j] ^ B[i][j]))
ok = false;
if (ok) {
int ops = 0;
for (int i = 0; i < n; i++) ops += r[i];
for (int j = 0; j < n; j++) ops += c[j];
ans = min(ans, ops);
}
}
cout << (ans == INT_MAX ? -1 : ans) << "\n";
}
return 0;
}
[sol-Java]
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine().trim());
StringBuilder sb = new StringBuilder();
while (T-- > 0) {
int n = Integer.parseInt(br.readLine().trim());
int[][] A = new int[n][n];
int[][] B = new int[n][n];
for (int i = 0; i < n; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < n; j++)
A[i][j] = Integer.parseInt(st.nextToken());
}
for (int i = 0; i < n; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < n; j++)
B[i][j] = Integer.parseInt(st.nextToken());
}
int[] r = new int[n];
int[] c = new int[n];
int ans = Integer.MAX_VALUE;
for (int r0 = 0; r0 <= 1; r0++) {
r[0] = r0;
for (int j = 0; j < n; j++)
c[j] = (A[0][j] ^ B[0][j]) ^ r[0];
for (int i = 1; i < n; i++)
r[i] = (A[i][0] ^ B[i][0]) ^ c[0];
boolean ok = true;
outer:
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if ((r[i] ^ c[j]) != (A[i][j] ^ B[i][j])) {
ok = false;
break outer;
}
if (ok) {
int ops = 0;
for (int i = 0; i < n; i++) ops += r[i];
for (int j = 0; j < n; j++) ops += c[j];
ans = Math.min(ans, ops);
}
}
sb.append(ans == Integer.MAX_VALUE ? -1 : ans).append('\n');
}
System.out.print(sb);
}
}

京公网安备 11010502036488号