坑比异或方程组?
一开始看到有个人的高斯消元法用异或写的,而且极其简短,于是当时就想果然是大牛,怎么厉害的写法我肯定懂不了。没想到晚上看相关习题的时候才发现有这个异或方程组...这就很不清真了。博主说他理解了两天,可能我看的浅,也没觉得特别难。感觉大概可以用这样几个点来描述异或方程组:
1. 首先,这种方程组适用于对某个对象进行某种操作可以对其他对象产生一定影响,而且只有两种状态的情况,一般表示为1和0。
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. 异或方程组对状态的描述方式:
一.若i与j有关联,即操作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("");
}
}
}