【ACWing】884. 高斯消元解异或线性方程组

题目地址:

https://www.acwing.com/problem/content/886/

输入一个 n n n元异或方程组,包含 n n n个方程,系数为 0 0 0 1 1 1,右边常数项也是 0 0 0 1 1 1。求解之。方程为: { a 11 x 1 ∧ a 12 x 2 ∧ . . . ∧ a 1 n x n = b 1 a 21 x 1 ∧ a 22 x 2 ∧ . . . ∧ a 2 n x n = b 2 . . . a n 1 x 1 ∧ a n 2 x 2 ∧ . . . ∧ a n n x n = b n \begin{cases} a_{11}x_1\wedge a_{12}x_2\wedge...\wedge a_{1n}x_n = b_1\\a_{21}x_1\wedge a_{22}x_2\wedge...\wedge a_{2n}x_n = b_2\\...\\a_{n1}x_1\wedge a_{n2}x_2\wedge...\wedge a_{nn}x_n = b_n \end{cases} a11x1a12x2...a1nxn=b1a21x1a22x2...a2nxn=b2...an1x1an2x2...annxn=bn如果解不唯一,则输出“Multiple sets of solutions”,如果无解,就输出“No solution”。

数据范围:
1 ≤ n ≤ 100 1\le n\le 100 1n100

可以用高斯消元法(严格来说需要论证一下这个方程是不是和通常的线性方程组有类似的性质。取二元域 F 2 \mathbb{F}_2 F2,加法定义为异或,乘法定义为通常数的乘法,可以验证 ( { 0 , 1 } , ∧ , × ) (\{0,1\},\wedge, \times ) ({ 0,1},,×)确实是个域。乘法也可以取与操作,域也可以写成 ( { 0 , 1 } , ∧ , & ) (\{0,1\},\wedge, \& ) ({ 0,1},,&),这两个域完全等价。对于域上的线性方程组,结论都是类似的,所以高斯消元法也可以用)。思路参考https://blog.csdn.net/qq_46105170/article/details/113967176。代码如下:

#include <iostream>
using namespace std;

const int N = 110;

int n;
int a[N][N];

// 返回0是有唯一解,返回1是多组解,返回2是无解
int gauss() {
    
    
    int r, c;
    for (r = c = 0; c < n; c++) {
    
    
    	// 找到当前列的值为1的行
        int t = r;
        for (int i = r; i < n; i++)
            if (a[i][c]) {
    
    
                t = i;
                break;
            }
		
		// 如果都是0,就略过,继续遍历下一列
        if (!a[t][c]) continue;
		
		// 将当前列值为1的那行换到前面去
        for (int i = c; i <= n; i++) swap(a[t][i], a[r][i]);
		
		// 把主元下方的值都变成0
        for (int i = r + 1; i < n; i++)
            if (a[i][c])
                for (int j = c; j <= n; j++)
                    a[i][j] ^= a[r][j];

        r++;
    }

    if (r < n) {
    
    
        for (int i = r; i < n; i++)
        	// 如果有常数项是1,那么就会导致存在方程0 = 1,所以无解
            if (a[i][n]) return 2;

        return 1;
    }

	// 如果有唯一解,
    for (int i = n - 2; i >= 0; i--)
        for (int j = i + 1; j < n; j++)
        	// 这里的&其实就是乘法,而^其实就是加法
            a[i][n] ^= a[i][j] & a[j][n];
    
    return 0;
}

int main() {
    
    
    cin >> n;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n + 1; j++) 
            cin >> a[i][j];

    int res = gauss();

    if (res == 0)
        for (int i = 0; i < n; i++)
            cout << a[i][n] << endl;
    else if (res == 1) cout << "Multiple sets of solutions" << endl;
    else cout << "No solution" << endl;

    return 0;
}

时间复杂度 O ( n 3 ) O(n^3) O(n3),空间 O ( 1 ) O(1) O(1)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/114006857
今日推荐