poj1222(高斯消元法解异或方程组+开关问题)

题目链接:https://vjudge.net/problem/POJ-1222

题意:给定一个5×6的01矩阵,改变一个点的状态时它上下左右包括它自己的状态都会翻转,因为翻转2次等价与没有翻转,那么每个点要么不翻转,要么翻转一次,求最终要怎样翻转可以使得矩阵全0。

思路:

  做法1(枚举): 因为数据小,可以枚举第一行的所有可能,共1<<6种,之后的每一行都根据上一行决定,然后通过判断最后一行是否满足条件来判断这种方案是否可行。

  做法2(高斯消元法): 为了说的清楚,现在假定矩阵为2×3,比如为,现在要达到的目标状态是:

    现在要求6个灯的状态,相当于6个变量。另外有6个方程,分别表示6个点最终的状态。

    比如,对于第0个灯,能影响到它的就是第0、1、3盏灯,因此它的方程是: (1*x0) ^ (1*x1) ^ (0*x2) ^ (1*x3) ^ (0*x4) ^ (0*x5) =0,(式子右边的0表示第0盏灯最开始的状态)。

    同理第1盏灯的方程即为:(1*x0) ^ (1*x1) ^ (1*x2) ^ (0*x3) ^ (1*x4) ^ (0*x5) =1。

    因此可以列出6个方程,然后用高斯消元法来求解,异或方程组的处理和普通线性方程组是一样的。

    对于题目就是5×6=30个方程,30个变量分别表示30盏灯的状态。

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;

const int maxn=40;
int T,cas,a[maxn][maxn],ans[maxn];

void init(){
    memset(a,0,sizeof(a));
    memset(ans,0,sizeof(ans));
    for(int i=0;i<5;++i){
        for(int j=0;j<6;++j){
            int t=i*6+j;
            a[t][t]=1;
            if(i>0) a[t][t-6]=1;
            if(i<4) a[t][t+6]=1;
            if(j>0) a[t][t-1]=1;
            if(j<5) a[t][t+1]=1;
        }
    }
}

void Gauss(int equ,int var){
    int r=0,c=0;
    for(;r<equ&&c<var;++r,++c){
        int Maxr=r;
        for(int i=r+1;i<equ;++i)
            if(abs(a[i][c])>abs(a[Maxr][c]))
                Maxr=i;
        if(a[Maxr][c]==0){
            --r;
            continue;
        }
        if(Maxr!=r){
            for(int i=c;i<=var;++i)
                swap(a[r][i],a[Maxr][i]);
        }
        for(int i=r+1;i<equ;++i){
            if(a[i][c]==0) continue;
            for(int j=c;j<=var;++j)
                a[i][j]^=a[r][j];
        }
    }
    for(int i=var-1;i>=0;--i){
        ans[i]=a[i][var];
        for(int j=i+1;j<equ;++j)
            ans[i]^=(a[i][j]&ans[j]);
    }
}

int main(){
    scanf("%d",&T);
    while(T--){
        init();
        for(int i=0;i<30;++i)
            scanf("%d",&a[i][30]);
        Gauss(30,30);
        printf("PUZZLE #%d
",++cas);
        for(int i=0;i<5;++i){
            for(int j=0;j<6;++j){
                printf("%d",ans[i*6+j]);
                if(j!=5) printf(" ");
            }
            printf("
");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/FrankChen831X/p/11769946.html