【高斯消元】【异或方程组】poj1222 EXTENDED LIGHTS OUT

由于每个点的状态受到其自身和周围四个点的影响,所以可以这样建立异或方程组:

引用题解:

http://hi.baidu.com/ofeitian/item/9899edce6dc6d3d297445264

题目大意:给你一个5*6的矩阵,矩阵里每一个单元都有一个灯和一个开关,如果按下此开关,那么开关所在位置的那个灯和开关前后左右的灯的状态都会改变(即由亮到不亮或由不亮到亮)。给你一个初始的灯的状态,问怎样控制每一个开关使得所有的灯最后全部熄灭(此题保证有唯一解)。

解题思路:高斯消元。很显然每个灯最多只需要按1下(因为按两下和没有按是一个效果)。我们可以定义30和未知数x0、x1.......x29代表每一个位置的开关是否被按。那么对于每一个灯的状态可以列一个方程,假设位置(i,j)处的开关为x(i*6+j),那么我们就可以列出方程:
x(i*6+j)+x((i-1)*6+j)+x((i+1)*6+j)+x(i*6+j-1)+x(i*6+j+1) = bo(mod 2)
(括号里的数字为x的下标,这里假设这些下标都是符合要求的,即都在矩形内,如果不在则可以去掉,当这个灯初始时是开着的,那么bo为1,否则为0)
这样可以列出30个方程,然后用高斯消元解这个方程组即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 31
const int dx[]={0,-1,0,1},dy[]={-1,0,1,0},n=30;
bool b[N],x[N],B[N][N+1],A[N][N+1];
int T,id[7][8];
void Madoka()
{
	memcpy(B,A,sizeof(A));
	for(int i=1;i<=n;++i)
	  B[i][n+1]=b[i];
	for(int i=1;i<=n;++i)
	  {
	  	int j=i;
	  	for(;j<=n;++j)
	  	  if(B[j][i])
	  	    break;
	  	swap(B[j],B[i]);
	  	for(int j=1;j<=n;++j)
	  	  if(j!=i&&B[j][i])
	  	    for(int k=1;k<=n+1;++k)
	  	      B[j][k]^=B[i][k];
	  }
	for(int i=1;i<=n;++i) x[i]=B[i][n+1];
}
int main()
{
	int pen=0;
	for(int i=1;i<=5;++i)
	  for(int j=1;j<=6;++j)
	    id[i][j]=++pen;
	scanf("%d",&T);
	for(int i=1;i<=T;++i)
	  {
	  	memset(A,0,sizeof(A));
	  	for(int j=1;j<=5;++j)
	  	  for(int k=1;k<=6;++k)
	  	    {
	  	      scanf("%d",&b[id[j][k]]);
	  	      A[id[j][k]][id[j][k]]=1;
	  	    }
	  	for(int j=1;j<=5;++j)
	  	  for(int k=1;k<=6;++k)
	  	    for(int l=0;l<4;++l)
	  	      if(id[j+dx[l]][k+dy[l]])
	  	        A[id[j][k]][id[j+dx[l]][k+dy[l]]]=1;
	  	Madoka();
	  	printf("PUZZLE #%d
",i);
	  	for(int j=1;j<=5;++j)
	  	  {
	  	  	for(int k=1;k<6;++k)
	  	  	  printf("%d ",x[id[j][k]]);
	  	  	printf("%d
",x[id[j][6]]);
	  	  }
	  }
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/4346311.html