<题目链接>
题目大意:
有一个5*6的矩阵,每一位是0或者1。 没翻转一位,它的上下左右的数字也为改变。(0变成1,1变成0)。要把矩阵中所有的数都变成0。求最少翻转次数的方案,输出矩阵(需要翻转的地方用1表示,反则用0表示)。
解题分析:
利用高斯消元,把这30个开关想象成是30个方程,第i个开关状态对应于第i个方程的右边的值。左边的是所有能够影响到的开关的值。
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; const int N = 35; int a[N][N], ans[N]; int dx[5] = { 0,1,0,-1,0 }; int dy[5] = { 0,0,1,0,-1 }; int idx(int x, int y) { return (x - 1) * 6 + y; } void Gauss() { int i, j, k, l; memset(ans, 0, sizeof(ans)); for (i = 1, j = 1; i <= 30 && j <= 30; j++) { for (k = i; k <= 30; k++) if (a[k][j]) break; if (a[k][j]) { for (l = 1; l <= 31; l++) swap(a[i][l], a[k][l]); for (l = 1; l <= 30; l++) //debug从1开始(回代) { if (l != i && a[l][j]) for (k = 1; k <= 31; k++) a[l][k] ^= a[i][k]; //高斯消元的^异或运算; } i++; } } for (int j = 1; j<i; j++) ans[j] = a[j][31]; } int main() { int x, y, T, cas = 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", &a[idx(i, j)][31]); //这里是将该矩阵按列线性存储 for (int k = 1; k <= 4; k++) { x = i + dx[k]; y = j + dy[k]; if (x>5 || y>6 || x<1 || y<1) continue; a[idx(i, j)][idx(x, y)] = 1; //将这个点周围四个点全部置为1 } } for (int i = 1; i <= 30; i++) a[i][i] = 1; Gauss(); printf("PUZZLE #%d ", ++cas); for (int i = 1; i <= 30; i++) { printf("%d ", ans[i]); if (i % 6 == 0) printf(" "); } } return 0; }
2018-08-08