设输入矩阵为A,输出矩阵为B,目标矩阵为C(零矩阵)。
方便起见,矩阵行列下标均从1开始。
考虑A矩阵元素a(i,j),B矩阵中与其相邻的元素 b(i,j),b(i - 1, j),b(i + 1,j),b(i,j - 1),b(i,j + 1) (#)。
有c(i,j)= 0 = a(i,j) ^ (∑ b(i,j) % 2)。
进一步有a(i,j) ^ 0 = a(i,j) = a(i,j) ^ a(i,j) ^ (∑ b(i,j) % 2) = ∑ b(i,j) % 2 (*)。
进一步考虑异或与模2加之间的关系:∑ b(i,j) % 2 = ^ B(i, j),其中B(i,j)表示(#)式5个元素的集合。
带入(*):^ B(i, j) = a(i,j)。这是我们需要的方程组。
(注:考虑边界上的元素,只需将不在矩阵范围内的b元素全部置零即可。)
将b(i,j)映射到x((i - 1) * 5 + j)(x下标从1到5 * 6)。
下面考虑解异或方程组AX= B。(与前面的表达无关)
a11 * x1 ^ a12 * x2 ^...^ a1n * xn = b1 ①
...
an1 * x1 ^ an2 * x2 ^...^ann * xn = bn ②
A,X,B均为0-1矩阵。
考虑消元,现在看系数矩阵A的第一列,若全部元素均为0,直接转到下一列,并且有方程组有多解。
若存在ai1 = 1,将其与第一行交换(这样做的目的是为了得到上三角阵)。
此时只需考虑剩余所有 1 < j ≤ n, 且aj1 = 1。有:
a11 * x1 ^ a12 * x2 ^...^ a1n * xn = b1 ①
aj1 * x1 ^ aj2 * x2 ^...^ ajn * xn = bj ②
① ^ ②:
(a11 * x1 ^ a12 * x2 ^...^ a1n * xn) ^ (aj1 * x1 ^ aj2 * x2 ^...^ ajn * xn) = b1 ^ bj。
即:(a11 * x1 ^ aj1 * x1) ^ (a12 * x2 ^ aj2 * x2) ^...^ (a1n * xn ^ ajn * xn) = b1 ^ bj 。
易于验证:a * x ^ b ^ x = (a ^ b) * x,因此进一步有:
(a11 ^ aj1)*x1 ^ (a12 ^ aj2)*x2 ^ .... ^ (a1n ^ ajn)*xn = b1 ^ bj 。
因而第j行x1的系数更新为1 ^ 1 即0 。
对增广阵如此消元至得到上三角阵即可得到答案。
http://poj.org/problem?id=1222
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int maxx = 5; 6 const int maxy = 6; 7 const int maxm = maxx * maxy; 8 const int maxn = maxm + 10; 9 int A[maxn][maxn], B[maxn]; 10 int C[maxn][maxn]; 11 int dx[] = {0, 0, 0, -1, 1}; 12 int dy[] = {0, -1, 1, 0, 0}; 13 int pos(int i, int j) { return (i - 1) * maxy + j; } 14 bool in_range(int i, int j) { return i >= 1 && i <= maxx && j >= 1 && j <= maxy; } 15 void solve(){ 16 memset(C, 0, sizeof C); 17 for(int i = 1, k = 1; i <= maxx; i++) for(int j = 1; j <= maxy; j++, k++){ 18 //the k-th column of the coefficient matrix 19 for(int u = 0; u < 5; u++){ 20 int nx = i + dx[u], ny = j + dy[u], p = pos(nx, ny); 21 if(in_range(nx, ny)) C[k][p] = 1; 22 } 23 C[k][maxm + 1] = A[i][j]; 24 } 25 for(int i = 1; i <= maxm; i++){ 26 //eliminate for X(i) 27 for(int j = i; j <= maxm; j++){ 28 //highlighting A[j][] 29 if(C[j][i]){ 30 swap(C[i], C[j]); 31 break; 32 } 33 } 34 for(int j = i + 1; j <= maxm; j++){ 35 if(!C[j][i]) continue; 36 for(int k = i; k <= maxm + 1; k++) C[j][k] ^= C[i][k]; 37 } 38 } 39 //retrieve the ans 40 for(int i = maxm; i >= 1; i--){ 41 B[i] = C[i][maxm + 1]; 42 for(int j = i + 1; j <= maxm; j++) if(C[i][j]) B[i] ^= B[j]; 43 } 44 for(int i = 1; i <= maxx; i++){ 45 printf("%d", B[pos(i, 1)]); 46 for(int j = 2; j <= maxy; j++){ 47 int p = pos(i, j); 48 printf(" %d", B[p]); 49 } 50 printf(" "); 51 } 52 } 53 54 int main(){ 55 freopen("in.txt", "r", stdin); 56 int T, kase = 0; 57 scanf("%d", &T); 58 while(T--){ 59 printf("PUZZLE #%d ", ++kase); 60 for(int i = 1; i <= maxx; i++) for(int j = 1; j <= maxy; j++) scanf("%d", &A[i][j]); 61 solve(); 62 } 63 return 0; 64 }