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

题目链接:http://poj.org/problem?id=1222

题目大意:现在有一个5行6列的矩阵,矩阵的每个格子都有一个灯泡,格子的值如果是1代表这个格子的灯泡是亮着的,如果是0就代表这个格子的灯泡是灭的。现在可以对矩阵的任意一个格子做如下操作,如果按下这个格子的按钮,那么这个格子及这个格子上面,下面,左边,右边的灯泡都会发生变化,如果灯泡一开始是亮着的,那么它就会熄灭,如果它是灭的,那么它就会亮起来。现在问你能否进行一系列操作令矩阵内所有的灯泡都熄灭。如果可以就输出操作的方案,如果不行就输出“-1”。

题目思路:这个题算是高斯消元的入门题了。我们先考虑如果对同一个格子进行一次操作的话,就会使其周围的格子发生变化,但再一次操作的话,这个效果又会消失了,所以对于每个格子我们都只需要进行一次操作即可。现在要使整个矩阵的灯泡都熄灭,对于每一个格子,它会被包括自己在内的五个格子所影响(上、下、左、右、自己),因为前面说了,多次操作后效果又会变回去,所以这些操作我们可以看成为异或操作,奇数次操作就会产生影响,偶数次就不会产生影响。接着就可以把每一格的影响作为矩阵的一行,既然最后要变化成全为0的矩阵,那么就是要找到一个可以异或成原矩阵的方案。这样就能借助高斯消元来解决。

具体实现看代码:

#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int MX = 30 + 5;
const int mod = 1e9 + 7;


int A[MX][MX], ans[MX], _;

void gauss(int equ, int var) {
	int max_r, col, k;
	for (k = 0, col = 0; k < equ && col < var; k++, col++) {
		max_r = k;
		for (int i = k + 1; i < equ; i++) {
			if (A[i][col] > A[max_r][col]) {
				max_r = i;
			}
		}
		if (A[max_r][col] == 0) {
			k--;
			continue;
		}
		if (max_r != k) {
			for (int j = col; j < var + 1; j++) {
				swap(A[k][j], A[max_r][j]);
			}
		}
		for (int i = k + 1; i < equ; i++) {
			if (A[i][col] != 0) {
				for (int j = col; j < var + 1; j++) {
					A[i][j] ^= A[k][j];
				}
			}
		}
	}
	for (int i = var - 1; i >= 0; i--) {
		ans[i] = A[i][var];
		for (int j = i + 1; j < var; j++) {
			ans[i] ^= (A[i][j] && ans[j]);
		}
	}
}

int main() {
	//FIN;
	int cas = 1;
	for (scanf("%d", &_); _; _--) {
		clr(ans); clr(A);
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 6; j++) {
				int id = i * 6 + j;
				A[id][id] = 1;
				if (i > 0) A[id - 6][id] = 1;
				if (i < 4) A[id + 6][id] = 1;
				if (j > 0) A[id - 1][id] = 1;
				if (j < 5) A[id + 1][id] = 1;
			}
		}
		for (int i = 0; i < 30; i++) scanf("%d", &A[i][30]);
		gauss(30, 30);
		printf("PUZZLE #%d\n", cas++);
		for (int i = 0; i < 30; i++)
			printf("%d%c", ans[i], i % 6 == 5 ? '\n' : ' ');
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Lee_w_j__/article/details/82150881