题目意思较简单,就是给你一个初始矩阵(里面每个元素代表一个开关),改变一个开关就可以使得在其上、下、左、右的开关的状态都改变。问若使得所有开关均关闭(开关开为1,关为0),则需要改变哪些开关,并给出要改变的开关的矩阵图,里面的元素为1的表示要改变的开关,为0的表示不要变的开关。
好高兴的是纠结了几天终于有点弄明白怎样根据所给的问题建立方程组了,这位大牛的blog给了我不少的启发:
http://hi.baidu.com/ofeitian/blog/item/9385662a30c2ebf7e7cd4016.html
让我最终明白了对于开关问题是要如何建立方程的。因为在我看来,不少数学题(这是我的分类,希望没误导到大家)既可以用搜索做,也可以用纯数学的方法做。这道题是一道很裸的高斯消元法的题目,就连它的输出也只是输出方程的根~~因此比较适合刚接触高斯消元法的人。我个人觉得高斯消元法所解决的题目很大一部分的难点在于如何找状态来建立方程组,至少初学者是这样的。这里讲讲我的一些体会,就是,在开关问题中,是要对所有的开关一一建立方程,因为所有开关都有最终的状态。由于开关间有联系,因此我们所构造的方程是“影响因素”方程,即方程中所有的未知数是可以直接影响到该开关的。未知数之间用下标来区分。方程构造完后就用高斯消元法来解方程,所得的解即为需要改变的开关(因为每个开关用下标一一对应好)。由于此题有30个灯,因此有30条方程。每个灯的方程为:
x(i*6+j)+x((i-1)*6+j)+x((i+1)*6+j)+x(i*6+j-1)+x(i*6+j+1)=b(mod 2)
括号内为下标,b为灯的初始状态,1为开,0为关。
最后套个高斯消元模版即可。
代码是抄的,只改了少许。。。。。
- #include "stdio.h"
#include "string.h" - const int N=50;
- int array[N][N],matrix[N][N];
int dir[4][2]={-1,0,1,0,0,-1,0,1};
int n; - bool check(int x,int y)
{
if(x>=0 && x<5 && y>=0 && y<6)
return true;
else return false;
} - void solve()
{
int i,j,k;
int row=0,col=0;
while(row<n && col<n)
{
int id=row;
for(i=row+1;i<n;i++)
if(matrix[i][col]>matrix[id][col]) id=i;
if(matrix[id][col])
{
for(i=col;i<=n;i++)
{
k=matrix[id][i];
matrix[id][i]=matrix[row][i];
matrix[row][i]=k;
}
for(i=row+1;i<n;i++)
if(matrix[i][col])
{
for(j=col;j<=n;j++)
matrix[i][j]^=matrix[row][j];
}
row++;
}
col++;
}
for(i=n-2;i>=0;i--)
{
for(j=i+1;j<n;j++)
matrix[i][n]^=(matrix[i][j] && matrix[j][n]);
}
for(i=0;i<n;i++)
{
printf("%d ",matrix[i][n]);
if((i+1)%6==0) printf("/n");
}
} - int main()
{
freopen("in.txt","r",stdin);
int t;
int cnt=1;
scanf("%d",&t);
while(t--)
{
memset(matrix,0,sizeof(matrix));
int i,j,k;
int x,y,a,b;
n=30;
for(i=0;i<5;i++)
for(j=0;j<6;j++)
{
scanf("%d",&array[i][j]);
a=i*6+j;
if(array[i][j]) matrix[a][n]=1;
matrix[a][a]=1;
for(k=0;k<4;k++)
{
x=i+dir[k][0];
y=j+dir[k][1];
if(check(x,y))
{
b=x*6+y;
matrix[a][b]=1;
}
}
}
printf("PUZZLE #%d/n",cnt);
solve();
cnt++;
}
return 0;
}