题意: 给出5*6的由0 / 1构成的矩阵,当改变一个位置上的值时,其周边四个的值也随之改变。
进行操作,使得矩阵全为0。
要点:1.操作没有先后顺序;
2.重复操作无意义;
3.第一行的操作确定之后,后续的操作将唯一确定。
知识点:位运算枚举,数组的备份与清空,找规律(重复性,关联性,顺序),二维坐标改值技巧
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int g[5][6], backup[5][6], res[5][6]; //backup为备份数组,res存操作结果
int dx[5] = {-1, 0, 1, 0, 0}, dy[5] = {0, 1, 0, -1, 0}; //自身及四周坐标,联动改值
void turn(int a, int b){ //改值函数
res[a][b] = 1;
for(int i = 0; i < 5; ++i){
int x = a + dx[i];
int y = b + dy[i];
if(x < 0 || y < 0 || x >= 5 || y >= 6) continue; //考虑界外情况
g[x][y] ^= 1; //异或运算,0 1互换
}
return;
}
int main(){
int n;
cin >> n;
for(int p = 1; p <= n; ++p){ //记录谜题序号
for(int i = 0; i < 5; ++i)
for(int j = 0; j < 6; ++j){
cin >> g[i][j];
}
memcpy(backup, g, sizeof g);
//二进制枚举
for(int op = 0; op < (1 << 6); ++op){ //用二进制数进行枚举
//复原
memcpy(g, backup, sizeof backup); //进行备份
memset(res, 0, sizeof res); //清空
//重置操作放在起始位置进行比较不易出错
//处理第一行
for(int j = 0; j < 6; ++j){
if( op >> j & 1 ) turn(0, j); //位运算 从右到左取出二进制的数
}
//处理剩下的行
for(int i = 0; i < 4; ++i)
for(int j = 0; j < 6; ++j){
if(g[i][j] == 1) turn(i + 1, j);
}
//检验最后一行
bool dark = true;
for(int i = 0; i < 6; ++i)
if(g[4][i] == 1){
dark = false; break;
}
//输出
if(dark){
cout << "PUZZLE #" << p << endl;
for(int i = 0; i < 5; ++i){
for(int j = 0; j < 6; ++j)
cout << res[i][j] << ' ';
cout << endl;
}
break;
}
}
}
return 0;
}