Description
给你一个5*6的矩阵,矩阵里每一个单元都有一个灯和一个开关,如果按下此开关,那么开关所在位置的那个灯和开关前后左右的灯的状态都会改变 (即由亮到不亮或由不亮到亮)。给你一个初始的灯的状态,问怎样控制每一个开关使得所有的灯最后全部熄灭。
Input
输入第一行整数N,代表有N组测试用例,每一组测试用例是一个56的矩阵,在56的矩阵里,0代表灯关闭,1代表灯开着。
Output
对于每一组数据,输出第一行包括字符串:“PUZZLE #m”,m是代表的是第m组数据,接着输出一个包含0,1的5*6的矩阵,(ij)处的0代表(i,j)处的开关没有按下,(ij)处的1代表(i,j)处的开关按下。
Sample Input
2
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
0 0 1 0 1 0
1 0 1 0 1 1
0 0 1 0 1 1
1 0 1 1 0 0
0 1 0 1 0 0
Sample Output
PUZZLE #1
1 0 1 0 0 1
1 1 0 1 0 1
0 0 1 0 1 1
1 0 0 1 0 0
0 1 0 0 0 0
PUZZLE #2
1 0 0 1 1 1
1 1 0 0 0 0
0 0 0 1 0 0
1 1 0 1 0 1
1 0 1 1 0 1
HINT
找出每个灯和开关之间的关系,列出方程组求解。
/可以把 56 的初始矩阵看成一个30 * 1的列向量(为了后面更好的列方程,所以看成列向量)Y(y1 ,y2 ,y3 ……y30) 。
然后把每一个开关也看成一个列向量C(k)(向量里总共30个值),那向量里的值是什么呢?如果第 k 个开关被按下影响了哪个灯就把相应位置为1,
否则置为0(例如:按第一个开关,1,2,7号灯会有影响,那么C(1) = {1 ,1 ,0 ,0 ,0 ,0 ,1 ,0,后面全为0},其它的开关也这样,
那么要是全部的开关关掉,
就必须 Y(y1 ,y2……y30) + x1 * C(k1) + x2 * C(k2) + x3 * C(k3) ……+x30 * C(k30) = (0 ,0 ,0……0) (再次强调等式里的向量都是列向量),
这里等式左边需要mod 2,其中等式中的 x1 ,x2 ……x30 为未知数,为0 或 1 ,1 代表操作了此按钮,0代表没操作,然
后我们把所有未知数看成一个列向量X(x1 ,x2 ,x3……x30),C(k1) ,C(k2) ……C(k30),也组成一个3030 的矩阵 A(C(k1) ,C(k2) ,C(k3)……C(k30))
(这里Y其实是一个对称向量,Y的转置等于Y),这样等式就变成了 AX = Y (mod 2) ,这样方程就列出来了。
然后为什么有唯一解呢?我们可以发现 r(A) = 30,也就是说 A 可逆,因为r(A) = r(A ,Y) = 30 = n
(注意 : 如果矩阵不是30 * 30 的这种形式的矩阵,则可能不是唯一解) ,所以方程一定有唯一解。好了下面就可以用高斯消元解方程了。
(因为此矩阵 A 为对称矩阵那么代码中完全可以将向量C(k) 组成 A矩阵的时候看成行向量)。*/
#include <stdio.h>
#include <math.h>
#include "string.h"
#include <stdlib.h>
int a[39][39],ans[39];
int x[5] = {-1 ,1 ,0 ,0 ,0} ,y[5] = {0 ,0 ,-1 ,1 ,0} ;
void gauss(int n,int m)
{
int max_r;
int k=0,col=0;
for(;k<n&&col<m;++k,++col)
{
max_r=k;
int i=0;
for(i=k+1;i<n;++i)
{
if(abs(a[max_r][col]) < abs(a[i][col]))
max_r = i ;
}
if(!a[max_r][col])
{
--k;
continue;
}
if(max_r!=k)
{
for(i=col;i<=m;++i)
{
int temp;
temp=a[k][i];
a[k][i]=a[max_r][i];
a[max_r][i]=temp;
}
}
for(i=k+1;i<n;++i)
{
if(a[i][col])
{
int j;
for(j=col;j<=m;++j)
a[i][j] = a[i][j]^a[k][j] ;
}
}
for( i = n-1 ; i >= 0 ; --i)
{
ans[i] = a[i][m] ;
int j;
for( j = i+1 ;j < m ; ++j)
ans[i] = ans[i]^(a[i][j]&&ans[j]) ;
}
}
}
void input(int n ,int m){
int i,j,k;
for( i = 0 ;i < n ; ++i){
for( j = 0 ;j < m ; ++j){
int t = i*m + j ;
scanf("%d" ,&a[t][n*m]) ;
for( k = 0 ;k < 5 ; ++k){
int sx = x[k] + i ;
int sy = y[k] + j ;
int st = sx*m + sy ;
if(sx >= 0 && sx < n && sy >= 0 && sy < m){
a[t][st] = 1 ;
}
}
}
}
}
int main()
{
int nn=0;
int i=0,j=0,jj,kk;
scanf("%d",&nn);
for(j=0;j<nn;++j)
{
const int n=5,m=6;
memset(a,0,sizeof(a));
memset(ans,0,sizeof(ans));
input(n,m);
gauss(n*m,n*m);
printf("PUZZLE #%d\n",j+1);
for(jj=0;jj<30;++jj)
{
if((jj+1)%6 == 0){
printf("%d\n" ,ans[jj]) ;
}else printf("%d " ,ans[jj]) ;
}
}
return 0;
}