首页 > 代码库 > UVA 1560 - Extended Lights Out(高斯消元)

UVA 1560 - Extended Lights Out(高斯消元)

UVA 1560 - Extended Lights Out

题目链接

题意:给定一个矩阵,1代表开着灯,0代表关灯,没按一个开关,周围4个位置都会变化,问一个按的方法使得所有灯都变暗

思路:两种做法:
1、枚举递推
这个比较简单,就枚举第一行,然后递推过去,每次如果上一行是亮灯,则下一行开关必须按下去

2、高斯消元,
这个做法比较屌一些,每个位置对应上下左右中5个位置可以列出一个异或表达式,然后30个位置对应30个异或表达式,利用高斯消元法就能求出每个位置的解了

代码:

高斯消元法:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int d[5][2] = {{0, 0}, {0, 1}, {0, -1}, {1, 0}, {-1, 0}};

int t, a[31][31], out[6][6];

void back() {
    for (int i = 29; i >= 0; i--) {
	out[i / 6][i % 6] = a[i][30];
	for (int j = 0; j < i; j++) {
	    if (a[j][i])
		a[j][30] ^= a[i][30];
	}
    }
}

void guess() {
    for (int i = 0; i < 30; i++) {
	int k = i;
	for (; k < 30; k++)
	    if (a[k][i]) break;
	for (int j = 0; j <= 30; j++)
	    swap(a[i][j], a[k][j]);
	for (int j = i + 1; j < 30; j++) {
	    if (a[j][i]) {
		for (int k = i; k <= 30; k++)
		    a[j][k] ^= a[i][k];
	    }
	}
    }
    back();
}

int main() {
    int cas = 0;
    scanf("%d", &t);
    while (t--) {
	memset(a, 0, sizeof(a));
	for (int i = 0; i < 30; i++)
	    scanf("%d", &a[i][30]);
	for (int i = 0; i < 30; i++) {
	    int x = i / 6, y = i % 6;
	    for (int j = 0; j < 5; j++) {
		int xx = x + d[j][0];
		int yy = y + d[j][1];
		if (xx < 0 || xx >= 5 || yy < 0 || yy >= 6) continue;
		a[i][xx * 6 + yy] = 1;
	    }
	}
	guess();
	printf("PUZZLE #%d\n", ++cas);
	for (int i = 0; i < 5; i++) {
	    for (int j = 0; j < 5; j++)
		printf("%d ", out[i][j]);
	    printf("%d\n", out[i][5]);
	}
    }
    return 0;
}


枚举递推:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int d[5][2] = {{0, 0}, {1, 0}, {-1, 0}, {0, 1}, {0, -1}};
const int N = 6;
int t, g[N][N], tmp[N][N], out[N][N];

bool judge(int s) {
    memset(out, 0, sizeof(out));
    for (int i = 0; i < 5; i++)
	for (int j = 0; j < 6; j++)
	    tmp[i][j] = g[i][j];
    for (int i = 0; i < 6; i++) {
	if (s&(1<<i)) {
	    out[0][i] = 1;
	    for (int j = 0; j < 5; j++) {
		int xx = d[j][0];
		int yy = i + d[j][1];
		if (xx < 0 || yy < 0 || xx >= 5 || yy >= 6) continue;
		tmp[xx][yy] = (!tmp[xx][yy]);
	    }
	}
    }
    for (int i = 1; i < 5; i++) {
	for (int j = 0; j < 6; j++) {
	    if (tmp[i - 1][j]) {
		out[i][j] = 1;
		for (int k = 0; k < 5; k++) {
		    int xx = i + d[k][0];
		    int yy = j + d[k][1];
		    if (xx < 0 || yy < 0 || xx >= 5 || yy >= 6) continue;
		    tmp[xx][yy] = (!tmp[xx][yy]);
		}
	    }
	}
    }
    for (int i = 0; i < 6; i++)
	if (tmp[4][i]) return false;
    return true;
}

void solve() {
    for (int i = 0; i < (1<<6); i++)
	if (judge(i)) return;
}

int main() {
    int cas = 0;
    scanf("%d", &t);
    while (t--) {
	for (int i = 0; i < 5; i++)
	    for (int j = 0; j < 6; j++)
		scanf("%d", &g[i][j]);
	solve();
	printf("PUZZLE #%d\n", ++cas);
	for (int i = 0; i < 5; i++) {
	    for (int j = 0; j < 5; j++)
		printf("%d ", out[i][j]);
	    printf("%d\n", out[i][5]);
	}
    }
    return 0;
}