AOJ 2140 - Tile Puzzle
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2140
概要
N * N のタイルがあり,最初すべてのタイルの色は 0 である.
あるタイルに触れると,そのタイルと隣接する8マスのタイルの色が1つ進む. タイルの色は 7 種類で,色 6 の次は色 0 になる. また,一番上のマスと一番下のマスは隣接しているとし,同様に一番左のマスと一番右のマスも隣接しているとする.
最終的な色の配置が与えられるので,どのマスを何回触れればよいかを答える. ただし,そのような配置にすることができない場合は -1 のみを出力する.
制約
- 3 <= N <= 15
解法
いわゆる Lights Out とか Flip It と呼ばれるゲーム.
マス (i, j) に触れる回数を x[i,j]
,最終的な色を a[i,j]
とすると,N*N
個の一次方程式が立つので,連立方程式とみて有限体 F_7 の上でガウスの消去法で解くことで求めることができる.
なぜか AOJ でジャッジができないので,2008/Practice/夏合宿 - ACM-ICPC Japanese Alumni Group からインプットを取ってきて手元で確認した.
aoj/2140.cc1 #include <cstdio> 2 #include <vector> 3 using namespace std; 4 5 struct mod 6 { 7 int m; 8 mod(int a) : m(a) {} 9 int operator()(int x) const { return ((x%m)+m)%m; } 10 }; 11 12 static mod M(7); 13 int inv_tbl[7] = {-1, 1, 4, 5, 2, 3, 6}; 14 15 vector<int> gaussian_elimination(vector<vector<int> > a, vector<int> b) 16 { 17 const int N = a.size(); 18 vector<int> sigma(N); 19 for (int i = 0; i < N; i++) { 20 sigma[i] = i; 21 } 22 23 for (int i = 0; i < N; i++) { 24 for (int j = i+1; a[i][i] == 0 && j < N; j++) { 25 swap(a[i], a[j]); 26 swap(b[i], b[j]); 27 swap(sigma[i], sigma[j]); 28 } 29 if (a[i][i] == 0) { 30 continue; 31 } 32 33 const int t = inv_tbl[a[i][i]]; 34 for (int k = i; k < N; k++) { 35 a[i][k] = M(a[i][k] * t); 36 } 37 b[i] = M(b[i] * t); 38 39 for (int j = 0; j < N; j++) { 40 if (i == j) { 41 continue; 42 } 43 const int u = a[j][i]; 44 for (int k = i; k < N; k++) { 45 a[j][k] = M(a[j][k] - u*a[i][k]); 46 } 47 b[j] = M(b[j] - u*b[i]); 48 } 49 } 50 51 for (int i = 0; i < N; i++) { 52 if (a[sigma[i]][sigma[i]] == 0 && b[sigma[i]] != 0) { 53 return vector<int>(); 54 } 55 } 56 return b; 57 } 58 59 int main() 60 { 61 int N; 62 while (scanf("%d", &N) != EOF && N != 0) { 63 const mod K(N); 64 vector<vector<int> > a(N*N, vector<int>(N*N, 0)); 65 for (int i = 0; i < N; i++) { 66 for (int j = 0; j < N; j++) { 67 for (int k = -1; k <= 1; k++) { 68 for (int l = -1; l <= 1; l++) { 69 a[N*i+j][N*K(i+k)+K(j+l)] = 1; 70 } 71 } 72 } 73 } 74 vector<int> b(N*N); 75 for (int i = 0; i < N*N; i++) { 76 scanf("%d", &b[i]); 77 } 78 79 const vector<int> x = gaussian_elimination(a, b); 80 if (x.empty()) { 81 puts("-1"); 82 } else { 83 for (int i = 0; i < N; i++) { 84 for (int j = 0; j < N; j++) { 85 if (j != 0) { 86 putchar(' '); 87 } 88 printf("%d", x[N*i+j]); 89 } 90 putchar('\n'); 91 } 92 } 93 putchar('\n'); 94 } 95 return 0; 96 }