一、题意理解
游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
使用windows自带的画图,摁住shift拖动鼠标画出下列的图形进行演示。
样例演示:
二、每一行开关的操作完全由前一行灯的亮灭决定
三、细节敲定
11010 => 对应第26个操作。那么0 ~ 2 5 2^5 25-1就可以逐一对应枚举第一行会有的32种方案
开关点亮函数
点击一个位置的开关以后,它上下左右四个位置的开关都会被改变状态。用四个 i f if if就显得太麻烦了。这里考虑的是通过添加偏移量实现。
时间复杂度
32 ∗ 25 ∗ 5 ∗ 500 = 2000000 32 * 25 * 5 * 500 = 2000000 32∗25∗5∗500=2000000,大概是两百万次的运算。是完全没有问题的
#include
#include
#include
#include
using namespace std;
const int N = 6;
char g[N][N],backup[N][N];
int dx[] = {-1,0,1,0,0} , dy[] = {0,-1,0,1,0};
//补全turn 函数
void turn(int x,int y)
{
for(int i = 0; i < 5;i++)
{
int a = x+dx[i] , b = y + dy[i];
//判断边界
if(a < 0 || a >= 5 || b < 0 || b>= 5) continue;
//更新状态
g[a][b] ^= 1;
}
}
int main()
{
int T;
cin >> T;
while(T--)
{
//构建地图
for(int i = 0; i < 5;i++) cin >> g[i];
int res = 10;//记录答案
//枚举第一行的32种选择
for(int op = 0; op < 32;op++)
{
memcpy(backup,g,sizeof g);
int step = 0;//记录执行的步骤
//处理当前这个方案是否有可以摁亮的灯
for(int i = 0; i < 5; i++)
{
if(!(op >> i &1))
{
step ++;
turn(0,i);
}
}
//根据第一行现在的情况,处理后面四行的处理情况
for(int i = 0; i < 4;i++)
{
for(int j = 0; j < 5;j++)
if(g[i][j] == '0')
{
step ++;
turn(i+1,j);
}
}
//遍历最后一行,倘若有黑的灯,那么当前方案失败
bool dark = false;//标记
for(int i = 0; i < 5;i++)
if(g[4][i] == '0')
{
dark = true;
break;
}
if(!dark) res = min(res,step);
memcpy(g,backup,sizeof g);//从备份中把数据拿回来
}
if(res > 6) res = -1;//res = -1代表无解
cout << res << endl;
}
return 0;
}