题目:
题意:
给出一些01状态,按动一个按键与其相邻的4个和它本身的状态会取反,求使其全部变成0的按动方案。
题解:
我记得以前摩尔庄园有一个这样的游戏,而我当时只知道瞎摁。
可以发现灯的开关状态只和按下开关次数的奇偶性有关,那么可以构造异或方程组的模型。把每个开关按或没按设成未知量xi,如果按了就赋值为1,没按就赋值为0,那么可以发现某个灯状态改没改变取决于它自己的开关和所有与它相连的开关。按照相连状态建立矩阵,对于每个灯建立一个方程,把所有会影响到它的开关对应的系数赋值为1,不会影响到它的就赋值为0。常数项b对应着这个灯的目标状态,然后解异或方程组就可以了。
—–引自ATP学姐
代码:
#include <cstdio>
#include <bitset>
#include <cstring>
using namespace std;
bitset <35> a[35];
int ans[35],b[35],s[10][10];
void gauss()
{
for (int i=1;i<=30;i++)
{
if (a[i][i]==0)
{
int num=i;
for (int j=i+1;j<=30;j++)
if (a[i][j]) {num=j; break;}
swap(a[i],a[num]); swap(b[i],b[num]);
}
for (int j=i+1;j<=30;j++)
if (a[j][i]) a[j]^=a[i],b[j]^=b[i];
}
for (int i=30;i>=1;i--)
{
ans[i]=b[i];
for (int j=1;j<i;j++)
if (a[j][i]) b[j]^=ans[i];
}
}
int main()
{
int T,id=0;scanf("%d",&T);
while (T--)
{
memset(a,0,sizeof(a));
for (int i=1;i<=5;i++)
for (int j=1;j<=6;j++)
scanf("%d",&s[i][j]);
for (int i=1;i<=5;i++)
for (int j=1;j<=6;j++)
{
int t=(i-1)*6+j;
a[t][t]=1;
if (i!=1) a[t][t-6]=1;
if (j!=1) a[t][t-1]=1;
if (i!=5) a[t][t+6]=1;
if (j!=6) a[t][t+1]=1;
if (s[i][j]) b[t]=1;
else b[t]=0; ////b要清零哦
}
gauss();
printf("PUZZLE #%d\n",++id);
for (int i=1;i<=5;i++)
{
for (int j=1;j<=6;j++) printf("%d ",ans[(i-1)*6+j]);
printf("\n");
}
}
}