POJ - 3279链接
这道题好像是跟我之前的一个博客反转开关是一样的吧,好像是,还是重新写一篇博客吧。
我们知道第一排的灯一共有 1 << n - 1种,我们假定如果第其二进制数第 i 位是 1 代表摁下开关,0 代表不摁开关。
先枚举第一行的操作,那么操作完后第一行一定有的灯是亮的,有的灯是灭的。因为第一行已经操作完了,所以这一行的灯我们只能通过下一行对应的灯来使其熄灭,以此类推。
最后我们只要检查最后一行的灯是否都是灭的,如果是则符合要求(好像我这里检查了所有灯的状态)。
//Powered by CK
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 20;
const int ax[5] = {1, -1, 0, 0, 0};
const int ay[5] = {0, 0, 0, 1, -1};
int maze[N][N], ans[N][N], back[N][N], n, m;
void turn(int x, int y) {//摁下开关的一系列变化
for(int i = 0; i < 5; i++) {
int tempx = x + ax[i];
int tempy = y + ay[i];
maze[tempx][tempy] ^= 1;
}
}
bool judge() {//这里只要检查最后一行就行了,当时脑子可能不够清晰吧。
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
if(maze[i][j]) return false;
return true;
}
void solve() {
memcpy(back, maze, sizeof back);
for(int k = 0; k < 1 << m; k++) {
memset(ans, 0, sizeof ans);//注意一定要恢复最开始的状态。
memcpy(maze, back, sizeof maze);
for(int i = 1; i <= m; i++)
if(k >> i - 1 & 1) {
ans[1][i] = 1;
turn(1, i);
}
for(int i = 1; i < n; i++)
for(int j = 1; j <= m; j++) {
if(maze[i][j] == 1) {
ans[i + 1][j] = 1;
turn(i + 1, j);
}
}
if(judge()) {
for(int i = 1; i <= n; i++)
for(int j = 1; j<= m; j++)
printf("%d%c", ans[i][j], j == m ? '
' : ' ');
return ;
}
}
puts("IMPOSSIBLE");
}
int main() {
while(scanf("%d %d", &n, &m) != EOF) {
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin >> maze[i][j];
solve();
}
return 0;
}