pku 1222 EXTENDED LIGHTS OUT 解题报告 之高斯消去法
之前我写了这题的解题报告,但并不是最优化的方法。有点像模拟的那种。还好,经过算法导论这个群上的牛人指导,现在我终于可以用到了最优的方法——高斯消去法。十分感谢那位牛人。年龄还比我小呢。要加油才行。感觉数学很强,很中用。自己在大一并没有疯狂学好数学,现在可真后悔。
思路:首先我应该想想,press一次(i,j)的灯,影响其上下左右的灯,这就好比就相当于对整个灯盘做了一次线性变换。想明白这一点十分重要(相信你能想明白~~~~(*^__^*) 嘻嘻……)~。那么我们就可以将结果30个假设为30个未知量x。输入的灯初始状态作为线性方程组右端的30个值,那么其线性方程组左端的系数怎么求呢?其实我已经说了,当press一次(i,j)的灯,相当于一次线性变换,那么求出每个灯翻转一次,受影响的灯,即其他xi值,变换得:x1+···+xi=ans(i)。
想明白这个数学模型,问题就很好解决。剩下就是套用高斯消去法的模板了。但要注意一点就是结果要%2。
AC代码:
#include <iostream> using namespace std; #define N 30 bool fr[N]; int f[N][N], ans[N], x[N], n, t; int dr[4] = {-1, 1, 0, 0}; int dc[4] = {0, 0, -1, 1}; void set(int i, int r, int c) { int j = r * 6 + c; f[i][j] = 1; } void init() { int r, c; memset(f, 0, sizeof(f)); for (int i = 0; i < n; i++) { //第i块影响哪些 r = i / 6, c = i % 6; set(i, r, c); if (r > 0) { set(i, r + dr[0], c + dc[0]); } if (r < 4) { set(i, r + dr[1], c + dc[1]); } if (c > 0) { set(i, r + dr[2], c + dc[2]); } if (c < 5) { set(i, r + dr[3], c + dc[3]); } } } int Guass() { int t, i, j, k, temp; bool flag; for (t = 0; t < n; t++) { if (f[t][t] == 0) { flag = false; for (i = t + 1; i < n; i++) { if (f[i][t] != 0) { flag = true; for (k = 0; k < n; k++) { temp = f[t][k]; f[t][k] = f[i][k]; f[i][k] = temp; } temp = ans[t]; ans[t] = ans[i]; ans[i] = temp; break; } } if (!flag) { return 1; } } for (i = t + 1; i < n; i++) { if (f[i][t] != 0) { temp = f[i][t]; for (j = t; j < n; j++) { f[i][j] = (f[i][j] * f[t][t]) % 2; f[i][j] = (f[i][j] - f[t][j] * temp + 2) % 2; } ans[i] = (ans[i] * f[t][t] - ans[t] * temp + 2) % 2; } } } for (i = n - 1; i >= 0; i--) { temp = ans[i]; for (j = n - 1; j > i; j--) { temp = (temp - f[i][j] * x[j] + 2) % 2; } x[i] = ((temp / f[i][i]) + 2) % 2; } return 0; } void print() { for (int i = 0; i < n; i++) { int t = i % 6; if (t) { printf(" "); } printf("%d", x[i]); if (t == 5) { printf("/n"); } } } int main() { scanf("%d",&t); for (int q = 1; q <= t; q++) { n = 30; for (int i = 0; i < n; i++) { scanf("%d", ans + i); } init(); printf("PUZZLE #%d/n",q); Guass(); print(); } return 0; }