您的位置:首页 > 其它

POJ 1222 EXTENDED LIGHTS OUT 高斯消元解异或方程组

2014-11-17 09:41 357 查看
题意:在5*6的矩阵内,每个格子都有一个灯。当你触摸一个格子时,会将该格子上的灯和相邻的四个格子灯的状态反转。现在给出矩阵内,每个灯的初始状态,问怎么样触摸格子,使所有的灯都变成熄灭。

思路:

灯的状态只有0和1,很容易想到二进制。对于一个开着的灯,我们要摁奇数次控制该灯的开关。对于灭着的灯,我们要摁偶数次控制该灯的开关。这就容易联想到二进制异或。这样,我们就能建立一个方程组,方程组的每个变量表示是否开关是否触摸。方程组的常数项表示希望的目标。

注意:每一列方程表示的是一个灯的开关情况,所以对于每个开关,要将系数放到每个灯上。

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>

using namespace std;

const int MAXN = 40;

//a is a matrix , l is represent free variable, ans store the answer

int a[MAXN][MAXN],ans[MAXN];
bool l[MAXN];
int dx[] = {0,0,0,-1,1};
int dy[] = {0,-1,1,0,0};

int guass(int a[][MAXN],bool l[],int ans[], int n)
{
int res = 0, r = 0;
memset(l,0,sizeof(bool) * n);
for(int i = 0; i < n; ++i){
for(int j = r; j < n; ++j){
if(a[j][i] == 1){
for(int k = i; k <= n; ++k)
swap(a[j][k],a[r][k]);
break;
}
}
if(a[r][i] == 0){
++res;
continue;
}
for(int j = 0; j < n; ++j){
if(j != r && a[j][i] == 1){;
for(int k = i; k <= n; ++k)
a[j][k] ^= a[r][k];
}
}
l[i] = true,++r;
}
for(int i = 0; i < n; ++i){
ans[i] = a[i]
;
}
return res;
}

int main(void)
{
//freopen("input.txt","r",stdin);
int T;
scanf("%d",&T);
for(int cas = 1; cas <= T; ++cas){
memset(a,0,sizeof(a));
int n = 5 * 6;
for(int i = 0; i < 5; ++i){
for(int j = 0; j < 6; ++j){
for(int k = 0; k < 5; ++k){
int x = i + dx[k], y = j + dy[k];
if(x >= 0 && x < 5 && y >= 0 && y < 6)
a[6 * x + y][6 * i + j] = 1;
}
scanf("%d",&a[6 * i + j]
);
}
}
guass(a,l,ans,n);
printf("PUZZLE #%d\n",cas);
for(int i = 0; i < 30; ++i)
printf("%d%c",ans[i], (i + 1) % 6 == 0?'\n':' ');
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: