70.Acwing基础课第884题-简单-高斯消元解异或线性方程组

70.Acwing基础课第884题-简单-高斯消元解异或线性方程组

题目描述

输入一个包含 n 个方程 n 个未知数的异或线性方程组。

方程组中的系数和常数为 0 或 1,每个未知数的取值也为 0 或 1。

求解这个方程组。

异或线性方程组示例如下:

M[1][1]x[1] ^ M[1][2]x[2] ^ … ^ M[1][n]x[n] = B[1]
M[2][1]x[1] ^ M[2][2]x[2] ^ … ^ M[2][n]x[n] = B[2]
…
M[n][1]x[1] ^ M[n][2]x[2] ^ … ^ M[n][n]x[n] = B[n]

其中 ^ 表示异或(XOR),M[i][j]表示第 i 个式子中 x[j] 的系数,B[i] 是第 i 个方程右端的常数,取值均为 0 或 1。

输入格式

\(第一行包含整数 n\)

\(接下来 n 行,每行包含 n+1 个实数,表示一个方程的 n 个系数以及等号右侧的常数\)

输出格式

\(如果给定线性方程组存在唯一解,则输出共 n 行,其中第 i 行输出第 i 个未知数的解\)

如果给定线性方程组存在多组解,则输出 Multiple sets of solutions

如果给定线性方程组无解,则输出 No solution

数据范围

1≤n≤100

输入样例:

3
1 1 0 1
0 1 1 0
1 0 0 1

输出样例:

1
0
0

代码:

// 包含基础输入输出、算法头文件
#include <iostream>
#include <algorithm>

using namespace std;

// 常量定义:N=110,最多支持100个未知数的异或线性方程组(留冗余)
const int N = 110;

int n;                  // n:方程组的未知数个数(也是方程个数)
int a[N][N];            // 增广矩阵:a[i][j]表示第i行第j列(0/1),最后一列a[i][n]是常数项(0/1)
                        // 异或方程组形式:a[i][0]x0 ^ a[i][1]x1 ^ ... ^ a[i][n-1]xn-1 = a[i][n]

// 高斯消元核心函数(异或版):求解异或线性方程组
// 返回值:0-有唯一解 | 1-有无穷多解 | 2-无解
// 最终解(若有唯一解)存储在a[i][n]中(第i个未知数的解)
int gauss()
{
    int c, r; // c:当前处理的列(未知数);r:当前处理的行(方程)
    // 遍历每一列(逐个消去未知数)
    for (c = 0, r = 0; c < n; c ++ )
    {
        // ========== 步骤1:找当前列第一个非0行作为主元行(异或无需选绝对值最大,非0即可) ==========
        int t = r; // 初始假设当前行是主元行
        for (int i = r; i < n; i ++ )
            if (a[i][c]) // 异或中只需判断是否为1(非0)
                t = i;

        // ========== 步骤2:判断当前列是否全为0(该未知数无法消元,跳过) ==========
        if (!a[t][c]) continue;

        // ========== 步骤3:将主元行交换到当前处理行(第r行) ==========
        for (int i = c; i <= n; i ++ ) swap(a[r][i], a[t][i]);

        // ========== 步骤4:消去当前列下方所有行的系数(化为0,异或特性) ==========
        for (int i = r + 1; i < n; i ++ )
            // 若当前行的该列系数为1,才需要消元
            if (a[i][c])
                // 从后往前遍历:异或主元行,消去当前列的1
                // 异或性质:1^1=0,0^1=1,0^0=0 → 刚好实现消元
                for (int j = n; j >= c; j -- )
                    a[i][j] ^= a[r][j];

        r ++ ; // 当前行处理完成,下一行待处理
    }

    // ========== 步骤5:判断解的情况 ==========
    // 若处理的行数 < 未知数个数(存在自由变量)
    if (r < n)
    {
        // 检查是否存在 0 = 1 的矛盾方程(无解)
        for (int i = r; i < n; i ++ )
            // 若常数项为1,系数全0 → 0 = 1,矛盾,无解
            if (a[i][n])
                return 2;
        // 无矛盾方程 → 有无穷多解
        return 1;
    }

    // ========== 步骤6:回代求解(异或版,消去上三角非对角元素) ==========
    // 从最后一行往前回代,利用异或性质消去上三角的1
    for (int i = n - 1; i >= 0; i -- )
        for (int j = i + 1; j < n; j ++ )
            // 异或版回代:a[i][n] = a[i][n] ^ (a[i][j] * a[j][n])
            // 因a[i][j]是0/1,乘法等价于按位与,最终效果是:若a[i][j]=1,则异或a[j][n]
            a[i][n] ^= a[i][j] * a[j][n];

    return 0; // 有唯一解
}

int main()
{
    // 输入未知数个数n
    cin >> n;

    // 输入增广矩阵:n行,每行n个系数(0/1) + 1个常数项(0/1)(共n+1列)
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n + 1; j ++ )
            cin >> a[i][j];

    // 调用高斯消元函数,获取解的情况
    int t = gauss();

    if (t == 0)
    {
        // 有唯一解,输出每个未知数的解(0/1)
        for (int i = 0; i < n; i ++ ) cout << a[i][n] << endl;
    }
    else if (t == 1) 
        puts("Multiple sets of solutions"); // 无穷多解
    else 
        puts("No solution"); // 无解

    return 0;
}
posted @ 2026-04-09 17:04  CodeMagicianT  阅读(8)  评论(0)    收藏  举报