异或方程组?

坑比异或方程组?

一开始看到有个人的高斯消元法用异或写的,而且极其简短,于是当时就想果然是大牛,怎么厉害的写法我肯定懂不了。没想到晚上看相关习题的时候才发现有这个异或方程组...这就很不清真了。博主说他理解了两天,可能我看的浅,也没觉得特别难。感觉大概可以用这样几个点来描述异或方程组:

1. 首先,这种方程组适用于对某个对象进行某种操作可以对其他对象产生一定影响,而且只有两种状态的情况,一般表示为10

2. 异或方程组的一般形式:

(a[1][1]*x[1])^(a[1][2]*x[2])^......^(a[1][n]^x[n])=y[1]

(a[2][1]*x[1])^(a[2][2]*x[2])^......^(a[2][n]^x[n])=y[2]

......

(a[i][1]*x[1])^(a[i][2]*x[2])^......^(a[i][n]^x[n])=y[i]

......

(a[m][1]*x[1])^(a[m][2]*x[2])^......^(a[m][n]^x[n])=y[m]

3. 异或方程组对状态的描述方式:

一.ij有关联,即操作i的话j会产生变化,那么a[j][i]=1,(一定注意是a[j][i]),若没有影响,则a[j][i]=0

二.若操作i,那么x[i]=1

三.计数时只计算系数不为0的情况,也就是选取进行了操作且产生了影响的项进行异或操作。

4. 异或方程组的解题方式与gauss消元法解线性方程组类似,不过把加减消元替换成了异或消元。

5.不同于线性方程组的求解,异或方程组可以通过状态压缩来枚举所有自由元的可能状态。

 模板代码:POJ 1222 EXTENDED LIGHTS OUT(拿原高斯消元模板改的,中间敲错了一个地方,又定义了一遍var,导致日常找错找了一上午......)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cmath>
#define maxn 110
using namespace std;
int a[maxn][maxn];
int x[maxn*maxn];
int xx[4]={0,0,1,-1};
int yy[4]={1,-1,0,0};
int tot,var;
int getmark(int r,int c){
    if (r>=1&&r<=5&&c>=1&&c<=6){
        return 6*(r-1)+c;
    }
    return 0;
}
void geta(int i,int j){
    int mark1=getmark(i,j);
    a[mark1][mark1]=1;
    for (int k=0;k<4;k++){
        int nx=i+xx[k];
        int ny=j+yy[k];
        int mark2=getmark(nx,ny);
        if (mark2!=-1){
            a[mark2][mark1]=1;
        }
    }
}
int gauss(){
    int maxr;
    int c=1;
    int k,i,j;
    int num=0;
    for (k=1;k<=tot&&c<=var;k++,c++){
        maxr=k;
        if (!a[k][c]){
            for (i=k+1;i<=tot;i++)if (a[i][c]){
                maxr=i;
                break;
            }
            if (maxr!=k)for (i=c;i<=var+1;i++)swap(a[k][i],a[maxr][i]);
        }
        if (a[k][c]==0){
            k--;
            continue;
        }
        for (i=k+1;i<=tot;i++){
            if (a[i][c]){
                for (j=c;j<=var+1;j++)a[i][j]^=a[k][j];
            }
        }
    }
    for (i=k;i<=tot;i++)if (a[i][var+1])return -1;
    if (k-1<var)return var-k+1;
    for (i=1;i<=30;i++)x[i]=a[i][31];
    for (i=var;i>=1;i--)
    for (j=i+1;j<=var;j++)
        if (a[i][j]*x[j])x[i]^=x[j];
    return 0;
}
int main(){
    int t,i,j,k,l,cas=0;
    scanf("%d",&t);
    while (t--){
        memset (a,0,sizeof(a));
        for (i=1;i<=30;i++){
            scanf("%d",&a[i][31]);
        }
        for (i=1;i<=5;i++)
        for (j=1;j<=6;j++)
            geta(i,j);
        var=tot=30;
        gauss();
        printf("PUZZLE #%d\n",++cas);
        for(i=1;i<=30;i++){
            printf("%d ",x[i]);
            if(i%6==0) puts("");
        }
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值