题目链接: http://poj.org/problem?id=1222
题意: 有一个 5 * 6 的初始矩阵, 1 表示一个亮灯泡, 0 表示一个不亮的灯泡. 对 (i, j) 位置进行一次操作则 (i, j), (i + 1, j), (i - 1, j), (i, j - 1), (i, j + 1) 位置的灯泡变为原来的相反状态, 输出一种能让所有灯泡都变成不亮状态的操作集合.
思路:
1. 可以先枚举第一行的所有操作集合, 2^6 种, 第一行的每一种操作后都得到一个灯泡状态集合, 然后再根据第一行的灯泡状态确定第二行的操作, 若 (1, j) 亮, 则(2, j) 必定要进行一次操作, 若(1, j) 不亮, 则 (2, j) 一定不能进行操作. 依次根据上一行的灯泡状态确定下一行的操作. 然后再对最后一行灯泡的状态进行检查, 若全部不亮则得到一个解.
代码:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 6 const int N = 5; 7 const int M = 6; 8 const int MAXN = 10; 9 int mp[MAXN][MAXN], sol[MAXN][MAXN]; 10 bool flag = false; 11 int cas; 12 13 bool check(void){ 14 int gel[MAXN][MAXN]; 15 memcpy(gel, mp, sizeof(mp)); 16 for(int i = 1; i <= M; i++){ 17 if(sol[1][i]){ 18 gel[1][i] ^= 1; 19 gel[1][i - 1] ^= 1; 20 gel[1][i + 1] ^= 1; 21 gel[2][i] ^= 1; 22 gel[0][i] ^= 1; 23 } 24 } 25 for(int i = 2; i <= N; i++){ 26 for(int j = 1; j <= M; j++){ 27 if(gel[i - 1][j]){ 28 sol[i][j] = 1; 29 gel[i][j] ^= 1; 30 gel[i][j - 1] ^= 1; 31 gel[i][j + 1] ^= 1; 32 gel[i - 1][j] ^= 1; 33 gel[i + 1][j] ^= 1; 34 }else sol[i][j] = 0; 35 } 36 } 37 for(int i = 1; i <= M; i++){ 38 if(gel[N][i]) return false; 39 } 40 printf("PUZZLE #%d\n", cas); 41 for(int i = 1; i <= N; i++){ 42 for(int j = 1; j <= M; j++){ 43 cout << sol[i][j] << " "; 44 } 45 cout << endl; 46 } 47 return true; 48 } 49 50 void dfs(int m){ 51 if(flag) return; 52 if(m > M){ 53 if(check()) flag = true; 54 return; 55 } 56 sol[1][m] = 1; 57 dfs(m + 1); 58 sol[1][m] = 0; 59 dfs(m + 1); 60 } 61 62 int main(void){ 63 int t; 64 cin >> t; 65 for(cas = 1; cas <= t; cas++){ 66 for(int i = 1; i <= N; i++){ 67 for(int j = 1; j <= M; j++){ 68 cin >> mp[i][j]; 69 } 70 } 71 flag = false; 72 dfs(1); 73 if(!flag){ 74 printf("PUZZLE #%d\n", cas); 75 cout << "inf" << endl; 76 } 77 } 78 return 0; 79 }