1. 程式人生 > >高斯消元法解01異或方程組(附poj 1222題解)

高斯消元法解01異或方程組(附poj 1222題解)

const int maxn=50;
//有equ個方程,var個變元。增廣矩陣行數為equ,列數為var+1
int equ,var;
int a[maxn][maxn]; //增廣矩陣
int x[maxn];  //解集
int free_x[maxn];
int free_num;
void init(){
    memset(a,0,sizeof(a));
    memset(x,0,sizeof(x));
    equ=30,var=30;
}
//返回-1表示無解,0代表是唯一解,並生成解集x[],否則返回自由變元個數
int Gauss(){
    int max_r,col,k;
    free_num=0;
    for(k=0,col=0;k<equ&&col<var;k++,col++){
        max_r=k;
        for(int i=k+1;i<equ;i++){
            if(abs(a[i][col])>abs(a[max_r][col]))
                max_r=i;
        }
        if(a[max_r][col]==0){
            k--;
            free_x[free_num++]=col;
            continue;
        }
        if(max_r!=k){
            for(int j=col;j<var+1;j++)
                swap(a[k][j],a[max_r][j]);
        }
        for(int i=k+1;i<equ;i++){
            if(a[i][col]!=0){
                for(int j=col;j<var+1;j++)
                    a[i][j]^=a[k][j];
            }
        }
    }
    for(int i=k;i<equ;i++)
        if(a[i][col]!=0)
            return -1;  //無解
    if(k<var) return var-k;  //解不唯一,返回解個數
    //解唯一,生成解集
    for(int i=var-1;i>=0;i--){
        x[i]=a[i][var];
        for(int j=i+1;j<var;j++)
            x[i]^=(a[i][j]&&x[j]);
    }
    return 0;
}

題意:5*6矩陣中有30個燈,操作一個燈,周圍的上下左右四個燈會發生相應變化 即由滅變亮,由亮變滅,如何操

     作使燈全滅?


分析:這個問題是很經典的高斯消元問題。同一個按鈕最多隻能被按一次,因為按兩次跟沒有按是一樣的效果。那麼

     對於每一個燈,用1表示按,0表示沒有按,那麼每個燈的狀態的取值只能是01。列出30個方程,30個變

     元,高斯消元解出即可,因為解只能是0或者1,所以方程組是一定有解。


#include<queue>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<set>
using namespace std;
const int maxn=50;
//有equ個方程,var個變元。增廣矩陣行數為equ,列數為var+1
int equ,var;
int a[maxn][maxn]; //增廣矩陣
int x[maxn];  //解集
int free_x[maxn];
int free_num;
void init(){
    memset(a,0,sizeof(a));
    memset(x,0,sizeof(x));
    equ=30,var=30;
}
//返回-1表示無解,0代表是唯一解,並生成解集x[],否則返回自由變元個數
int Gauss(){
    int max_r,col,k;
    free_num=0;
    for(k=0,col=0;k<equ&&col<var;k++,col++){
        max_r=k;
        for(int i=k+1;i<equ;i++){
            if(abs(a[i][col])>abs(a[max_r][col]))
                max_r=i;
        }
        if(a[max_r][col]==0){
            k--;
            free_x[free_num++]=col;
            continue;
        }
        if(max_r!=k){
            for(int j=col;j<var+1;j++)
                swap(a[k][j],a[max_r][j]);
        }
        for(int i=k+1;i<equ;i++){
            if(a[i][col]!=0){
                for(int j=col;j<var+1;j++)
                    a[i][j]^=a[k][j];
            }
        }
    }
    for(int i=k;i<equ;i++)
        if(a[i][col]!=0)
            return -1;  //無解
    if(k<var) return var-k;  //解不唯一,返回解個數
    //解唯一,生成解集
    for(int i=var-1;i>=0;i--){
        x[i]=a[i][var];
        for(int j=i+1;j<var;j++)
            x[i]^=(a[i][j]&&x[j]);
    }
    return 0;
}
int G[maxn][maxn];
int main() {
    freopen("in.txt","r",stdin);
    int T;
    cin>>T;
    int now=0;
    while(T--){
        for(int i=0;i<5;i++){
            for(int j=0;j<6;j++)
                scanf("%d",&G[i][j]);
        }
        init();
        for(int i=0;i<5;i++){
            for(int j=0;j<6;j++){
                int t=i*6+j;
                a[t][t]=1;
                a[t][30]=G[i][j];
                if(i>0)a[t][(i-1)*6+j]=1;
                if(i<4)a[t][(i+1)*6+j]=1;
                if(j>0)a[t][i*6+j-1]=1;
                if(j<5)a[t][i*6+j+1]=1;
            }
        }
        int k=Gauss();
        printf("PUZZLE #%d\n",++now);
        for(int i=0;i<5;i++){
            for(int j=0;j<6;j++){
                if(j!=0)cout<<" ";
                cout<<x[i*6+j];
            }
            cout<<endl;
        }
    }
    return 0;
}