POJ 1753 (高斯消元)

题意是把所有的字母都变成w或者b的最小步数.

跑两次01方程,取最小如果两次都无解就输出无解.板子题~

#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
#define maxn 333
#define free Free
#define n 4

int a[maxn][maxn];
char mp[maxn][maxn];
int free[maxn*maxn]; //标记自由元
int x[maxn*maxn], cnt; //解集 自由元个数

int Gauss () {
    int max_r, col, k; //最大的数在的行 当前处理的列
    cnt = 0; //自由元个数
    for (k = 0, col = 0; k < n*n && col < n*n; k++, col++) {
        max_r = k;
        for (int i = k+1; i < n*n; i++) { //找到最大的数所在的行
            if (abs (a[i][col]) > abs (a[max_r][col]))
                max_r = i;
        }
        if (max_r != k) { //交换最大的数所在的行和当前行
            for (int i = 0; i <= n*n; i++)
                swap (a[k][i], a[max_r][i]);
        }
        if (a[k][col] == 0) { //判断自由元 处理当前行的下一列
            k--;
            free[cnt++] = col;
            continue;
        }
        for (int i = k+1; i < n*n; i++) {
            if (a[i][col]) {
                for (int j = col; j <= n*n; j++) {
                    a[i][j] ^= a[k][j];
                }
            }
        }
    }

    for (int i = k; i < n*n; i++) { //判断无解情况
        if (a[i][col])
            return -1;
    }
    if (k < n*n)
        return n*n - k; //返回自由元个数

    for (int i = n*n-1; i >= 0; i--) { //回代
        x[i] = a[i][n*n];
        for (int j = i+1; j < n*n; j++)
            x[i] ^= (a[i][j] && x[j]);
    }
    return 0;
}

int solve () {
    memset (x, 0, sizeof x);
    memset (free, 0, sizeof free);
    int tot = Gauss ();
    if (tot == -1) {
        return -1;
    }
    else if (tot == 0) {
        int ans = 0;
        for (int i = 0; i < n*n; i++)
            ans += x[i];
        return ans;
    }
    else { //枚举自由元
        int ans = 11111;
        for (int i = 0; i < (1<<tot); i++) {
            int num = 0;
            for (int j = 0; j < tot; j++) {
                if (i&(1<<j)) { //这一个自由元取1
                    x[free[j]] = 1;
                    num++;
                }
                else x[free[j]] = 0;
            }
            for (int j = n*n-tot-1; j >= 0; j--) { //计算所有的非自由元
                int id;
                for (id = j; id < n*n; id++)
                    if (a[j][id])
                        break;
                x[id] = a[j][n*n];
                for (int l = id+1; l < n*n; l++) if (a[j][l]) {
                    x[id] ^= x[l];
                }
                num += x[id];
            }
            ans= min (ans, num);
        }
        return ans;
    }
}

int main () {
    //freopen ("in", "r", stdin);
    while (cin >> mp[0]) {
        memset (a, 0, sizeof a);
        for (int i = 1; i < n; i++) {
            cin >> mp[i];
        }

        memset (a, 0, sizeof a);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (mp[i][j] == 'w')
                    a[i*n+j][16] = 1;
                else
                    a[i*n+j][16] = 0;
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                a[i*n+j][i*n+j] = 1;
                int pos = i*n+j;
                if (i > 0)
                    a[(i-1)*n+j][pos] = 1;
                if (i < n-1)
                    a[(i+1)*n+j][pos] = 1;
                if (j > 0)
                    a[pos-1][pos] = 1;
                if (j < n-1)
                    a[pos+1][pos] = 1;
            }
        }
        int ans1 = solve ();

        memset (a, 0, sizeof a);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (mp[i][j] == 'b')
                    a[i*n+j][16] = 1;
                else
                    a[i*n+j][16] = 0;
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                a[i*n+j][i*n+j] = 1;
                int pos = i*n+j;
                if (i > 0)
                    a[(i-1)*n+j][pos] = 1;
                if (i < n-1)
                    a[(i+1)*n+j][pos] = 1;
                if (j > 0)
                    a[pos-1][pos] = 1;
                if (j < n-1)
                    a[pos+1][pos] = 1;
            }
        }
        int ans2 = solve ();

        if (ans1 == -1 && ans2 == -1)
            cout << "Impossible" << endl;
        else if (ans1 == -1)
            cout << ans2 << endl;
        else if (ans2 == -1)
            cout << ans1 << endl;
        else cout << min (ans1, ans2) << endl;
    }
    return 0;
}


你可能感兴趣的:(POJ 1753 (高斯消元))