In an extended version of the game Lights Out , is a puzzle with 5 rows of 6 buttons each (the actual puzzle has 5 rows of 5 buttons each). Each button has a light. When a button is pressed, that button and each of its (up to four) neighbors above, below, right and left, has the state of its light reversed. (If on, the light is turned off; if off, the light is turned on.) Buttons in the corners change the state of 3 buttons; buttons on an edge change the state of 4 buttons and other buttons change the state of 5. For example, if the buttons marked X on the left below were to be pressed, the display would change to the image on the right.
The aim of the game is, starting from any initial set of lights on in the display, to press buttons to get the display to a state where all lights are off. When adjacent buttons are pressed, the action of one button can undo the effect of another. For instance, in the display below, pressing buttons marked X in the left display results in the right display.
Note that the buttons in row 2 column 3 and row 2 column 5 both change the state of the button in row 2 column 4, so that, in the end, its state is unchanged.
Note:
1. It does not matter what order the buttons are pressed.
2. If a button is pressed a second time, it exactly cancels the effect of the first press, so no button ever need be pressed more than once.
3. As illustrated in the second diagram, all the lights in the first row may be turned off, by pressing the corresponding buttons in the second row. By repeating this process in each row, all the lights in the first four rows may be turned out. Similarly, by pressing buttons in columns 2, 3 ��, all lights in the first 5 columns may be turned off.
Write a program to solve the puzzle.
Input
The first line of the input is a positive integer n which is the number of puzzles that follow. Each puzzle will be five lines, each of which has six 0's or 1's separated by one or more spaces. A 0 indicates that the light is off, while a 1 indicates that the light is on initially.
Output
For each puzzle, the output consists of a line with the string: "PUZZLE #m", where m is the index of the puzzle in the input file. Following that line, is a puzzle-like display (in the same format as the input) . In this case, 1's indicate buttons that must be pressed to solve the puzzle, while 0's indicate buttons, which are not pressed. There should be exactly one space between each 0 or 1 in the output puzzle-like display.
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
Source: Greater New York 2002
题意:给出一张5*6的表格,每个表格有状态开或者关,对一个格子每操作一次,会对它本身及上下左右的格子状态取反。目标是使所有状态为关闭(0),输出操作矩阵,1表示操作,0表示不操作。
需要注意的两点:
①一个格子操作2次,和不操作的影响相同,所以只用考虑操作一次或者不操作;
②题中已表明一定存在可行方案。
因为是作为高斯消元的练习题,就用高斯消元的方法来做。感觉应该还有更简单的算法。
怎么来列方程组呢?
①一共有30个格子,设Xi为未知量,取值为0,1,分别代表第i格是否操作。
②对于初始矩阵中的格子i,ai表示其初始状态。
③对于每一个i,都可以列出方程 ai^xi^xj..^xn=0,其中xi、xj..xn代表操作会影响i的格子的操作方案,这样可以列出30个方程,再将ai移至等号右端,变形为xi^xj..^xn=ai,便是标准的可用高斯消元法的方程组。
怎么样来解这个方程呢?
①因为一定有解,但并不知道解是否唯一,所以方程在解的过程中可能出现自由未知量,需要用列主元素高斯消元法。
②高斯消元法解XOR方程的核心在于:^等价于+和-,所以,只需要在算数加减法的高斯消元法中,将+和-变成^运算即可。
下面帖代码:
#include "stdio.h"
#include "string.h"
#include "iostream"
using namespace std;
int a[33][33],b[33],u[33][33],l[33][33],z[33],x[33];
void init()
{
memset(b,0,sizeof(b));
memset(u,0,sizeof(u));
memset(l,0,sizeof(l));
memset(z,0,sizeof(z));
memset(x,0,sizeof(x));
for(int i=1;i<=30;i++)
{
scanf("%d",&b[i]);
}
}
void get_a()
{
a[1][1]=1,a[1][2]=1,a[1][7]=1;
a[25][25]=1,a[25][19]=1,a[25][26]=1;
a[6][6]=1,a[6][5]=1,a[6][12]=1;
a[30][30]=1,a[30][29]=1,a[30][24]=1;
for(int i=2;i<6;i++)
{
a[i][i]=1,a[i][i-1]=1,a[i][i+1]=1,a[i][i+6]=1;
}
for(int i=26;i<30;i++)
{
a[i][i]=1,a[i][i-1]=1,a[i][i+1]=1,a[i][i-6]=1;
}
for(int j=1;j<4;j++)
{
int i=6*j+1;
a[i][i]=1,a[i][i-6]=1,a[i][i+6]=1,a[i][i+1]=1;
}
for(int j=1;j<4;j++)
{
int i=6*j+6;
a[i][i]=1,a[i][i-6]=1,a[i][i+6]=1,a[i][i-1]=1;
}
for(int j=1;j<4;j++)
{
for(int w=2;w<=5;w++)
{
int m=j*6+w;
a[m][m]=1,a[m][m-1]=1,a[m][m+1]=1,a[m][m-6]=1,a[m][m+6]=1;
}
}
/*
for(int i=1;i<=30;i++)
{
for(int j=1;j<=30;j++)
printf("%d ",a[i][j]);
printf("\n");
}
*/
}
void get_ul()
{
for(int i=1;i<=30;i++)
for(int j=1;j<=30;j++)
u[i][j]=a[i][j];
for(int i=1;i<=29;i++)
{
l[i][i]=1;
for(int j=i+1;j<=30;j++)
{
l[j][i]=u[j][i]*u[i][i];
}
for(int j=i+1;j<=30;j++)
{
for(int w=i+1;w<=30;w++)
{
u[j][w]^=(l[j][i]*u[i][w]);
}
b[j]^=l[j][i]*b[i];
}
for(int j=i+1;j<=30;j++)
{
if(u[j][i+1]==1)
{
for(int w=1;w<=30;w++)
swap(u[i+1][w],u[j][w]);
swap(b[i+1],b[j]);
break;
}
}
}
}
void get_x()
{
for(int i=30;i>0;i--)
{
x[i]=b[i];
for(int j=30;j>i;j--)
{
x[i]^=(u[i][j]*x[j]);
}
}
}
int main()
{
int T;
scanf("%d",&T);
get_a();
for(int q=1;q<=T;q++)
{
init();
get_ul();
get_x();
/* printf("a:\n");
printf("u:\n");
for(int i=1;i<=30;i++)
{
for(int j=1;j<=30;j++)
printf("%d ",u[i][j]);
printf("\n");
}*/
printf("PUZZLE #%d\n",q);
for(int i=0;i<5;i++)
{
printf("%d %d %d %d %d %d\n",x[1+i*6],x[2+i*6],x[3+i*6],x[4+i*6],x[5+i*6],x[6+i*6]);
}
}
return 0;
}