高斯消元求解异或方程组

POJ1830 开关问题

对于解异或方程组,系数可以采用二进制压缩,如果系数太多可以使用bitset,但是如果少一点就可以使用下述的写法,更加简单快速

使用bitset的写法更正常的没什么区别,只是对应的消除变为异或操作,另外行变换也会更加简单

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[100], n, t, ans;
int main() {
    cin >> t;
    while (t--) {
        cin >> n;
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1, j; i <= n; i++) {
            scanf("%d", &j);
            a[i] ^= j;
            a[i] |= 1 << i; // a[i][i] = 1;-
        }
        int x, y;
        while (~scanf("%d%d", &x, &y) && x && y) {
            a[y] |= 1 << x; // a[y][x] = 1;
        }
        ans = 1;
        for (int i = 1; i <= n; i++) {
            // 找到最大的一个a[i],即主元位数最高的a[i] 
            for (int j = i + 1; j <= n; j++)
                if (a[j] > a[i]) swap(a[i], a[j]);
            // 消元完毕,有i-1个主元,n-i+1个自由元 
            if (a[i] == 0) { ans = 1 << (n - i + 1); break; }
            // 出现0=1的方程,无解
            if (a[i] == 1) { ans = 0; break; }
            // a[i]最高位的1作为主元,消去其他方程该位的系数 
            for (int k = n; k; k--)
                if (a[i] >> k & 1) {
                    for (int j = 1; j <= n; j++)
                        if (i != j && (a[j] >> k & 1)) a[j] ^= a[i];
                    break;
                }
        }
        if (ans == 0) puts("Oh,it's impossible~!!");
        else cout << ans << endl; 
    }
}

猜你喜欢

转载自www.cnblogs.com/033000-/p/10754340.html