题意:
给你一个5*6的矩阵,你可以在任意位置对这个位置及其上下左右(如果有的话)进行xor【读作:叉欧二 ( :-D) 】操作,求解在哪些地方进行。
思路:
0. 一个显而易见就超时的方法(2^30),枚举第i个灯是开是关 但为第一种方法提供了思路
1.好像可以枚举第一行,然后通过递推算中间的几行,判断最后一行成不成立。
2.高斯消元,30个异或方程。
自己写得第一发高斯消元(虽然代码比较冗长,但自己yy出来很鸡冻)
// by Sirius_Ren
#include <cstdio>
#include <cstring>
using namespace std;
int eli[35][35],ans[31],x[32],cases,tot;
void solve(){
for(int i=1;i<=30;i++)
if(~ans[i]&&eli[tot][i])eli[tot][31]=(eli[tot][31]+ans[i])%2;
for(int i=1;i<=30;i++)
if(eli[tot][i]&&ans[i]==-1)ans[i]=eli[tot][31];
tot--;
}
int main(){
scanf("%d",&cases);
for(int ii=1;ii<=cases;ii++){
memset(ans,-1,sizeof(ans));
memset(x,0,sizeof(x));
memset(eli,0,sizeof(eli));
tot=30;
for(int i=1;i<=30;i++)
scanf("%d",&eli[i][31]);
for(int i=1;i<=30;i++){
eli[i][i]=1;
if(i-6>0)eli[i][i-6]=1;
if(i+6<=30)eli[i][i+6]=1;
if(i%6)eli[i][i+1]=1;
if(i%6!=1)eli[i][i-1]=1;
}
for(int i=1;i<=29;i++)
for(int l=1;l<=30;l++)
if(eli[i][l]&&!x[l]){
x[l]=i;
for(int j=i+1;j<=30;j++)
if(eli[j][l])
for(int k=1;k<=31;k++)
eli[j][k]^=eli[i][k];
break;
}
solve();
for(int i=29;i>=1;i--)
for(int j=1;j<=30;j++)
if(x[j]==i){
solve();
break;
}
printf("PUZZLE #%d
",ii);
for(int i=1;i<=30;i++){
if(i%6)
printf("%d ",ans[i]);
else printf("%d
",ans[i]);
}
}
}