首页 > 试题广场 >

小O的矩阵变换

[编程题]小O的矩阵变换
  • 热度指数:177 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小O有两个 nn 列的01方阵 AB,他希望用最少的操作次数将 AB 变相等。具体的,每次操作他可以选择 A 矩阵的一行或者一列,将此行或列的所有数字进行反转,即:0变1, 1变0。

他想知道自己最少需要几次操作可以做到,或者永远无法做到,请你帮帮他吧。

输入描述:
每个测试文件均包含多个测试点。第一行输入一个整数 T\ (1\le T\le 10) 代表测试数据组数,每组测试数据描述如下:
第一行输入一个 n\ (1 \leq n \leq 4),表示方阵的长和宽。
此后 n 行,每行输入 n 个整数(保证为 0 或者 1),表示方阵 A
此后 n 行,每行输入 n 个整数(保证为 0 或者 1),表示方阵 B


输出描述:
对于每组测试数据,在一行上输出一个整数表示最少的操作次数,如果无法将 A 变为 B,输出 -1。
示例1

输入

2
2
0 1
1 0
1 0
0 1
2
0 1
1 1
0 0
0 0

输出

2
-1

说明

第一个测试数据:
0 1
1 0
操作一次第一行变成:
1 0
1 0
再操作第二行变成:
1 0
0 1

因此最少需要 2 次。
面向AC编程:
注意到测试样例中,可以通过反转的得到相同字符串的,往往只需要行反转一次,因此直接对比A与B的每行是否相同,若不同则默认可通过一次反转变得相同,即min_count++

还注意到,对于n为偶数的情况,如果矩阵A或矩阵B的1的数量一个为奇数,一个为偶数,那么因为偶数数量的列通过0-1反转无法改变数量的奇偶性,则A与B一定不能通过变换得到,所以需要返回-1;

对于n=1的情况直接处理就好,对于n=3的情况,没有考虑,直接默认return -1了;

可能因为测试样例少,这样就过了

#include <iostream>
#include <vector>
#include <bits/stdc++.h>
using namespace std;

// 判断两个矩阵是否完全相同
bool isSame(const vector<vector<int>>& A, const vector<vector<int>>& B) {
    int n = A.size();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (A[i][j] != B[i][j]) {
                return false;
            }
        }
    }
    return true;
}

// 判断两个矩阵的指定行是否相同
bool isSameRow(const vector<vector<int>>& A, const vector<vector<int>>& B, int row_idx) {
    int n = A.size();
    for (int j = 0; j < n; j++) {
        if (A[row_idx][j] != B[row_idx][j]) {
            return false;
        }
    }
    return true;
}

// 统计矩阵中1的个数
int count_1(const vector<vector<int>>& A) {
    int n = A.size();
    int num_1 = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (A[i][j] == 1) {
                num_1++;
            }
        }
    }
    return num_1;
}

int min_op_counts(const vector<vector<int>>& A, const vector<vector<int>>& B) {
    int n = A.size();
    if (n == 1) {
        if (A[0][0] == B[0][0]) {
            return 0;
        } else {
            return 1;
        }
    } else if (n >= 2) {  // 2^4 = 16()
        if (isSame(A, B)) return 0;
        else if (n != 3) {
            int min_count = 0;
            if (count_1(A) % 2 == 1) return -1;
            if (count_1(B) % 2 == 1) return -1;
            
            // 逐行对比,默认可以通过一次反转就相等,那么min_count+1
            for (int row_idx = 0; row_idx < n; row_idx++) {
                if (isSameRow(A, B, row_idx)) {
                    // 不操作当前行
                } else {
                    min_count++;  // 反转当前行
                }
            }
            return min_count;
        }
    }
    return -1;
}

int main() {
    int T;
    cin >> T;
    
    for (int t = 0; t < T; t++) {
        int n;
        cin >> n;
        vector<vector<int>> A(n, vector<int>(n));
        vector<vector<int>> B(n, vector<int>(n));
        
        // 输入矩阵A
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                cin >> A[i][j];
            }
        }
        // 输入矩阵B
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                cin >> B[i][j];
            }
        }
        
        cout << min_op_counts(A, B) << endl;
    }
    
    return 0;
}


发表于 2025-07-25 11:46:30 回复(2)