AcWing 95. xxx费解的开关(bfs)
原题链接
中等
作者:
All_
,
2024-03-30 01:46:32
,
所有人可见
,
阅读 2
#include<bits/stdc++.h>
using namespace std;
const int N = 10;
int n;
int dx[5] = {0,-1,0,1,0},dy[5] = {0,0,-1,0,1}; //根据位示图,x往下是减一,往上是加一,y往左是减一,往右是加一
//用这两个数组来执行开关灯操作对应的五个位置即上下左右和自身
char g[N][N],backup[N][N];
// 把(x, y)以及上下左右的灯都变成相反的颜色
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; //异或,不同为1,相同为0
}
}
int main()
{
cin >> n;
while(n -- )
{
for(int i = 0;i < 5;i ++ )cin >> g[i]; // 按行输入,把每一行当成一个字符串
int res = 10;
// 枚举第一行的32种按法,不管灯是亮是灭,把第一行所有情况(每盏灯都有亮和不亮两种情况,2^5=32)都按一遍
// 按每种情况的第一行,去遍历接下来的行
// 枚举32种第一行的按法只是可能会减少步数,找到最优解,如果直接从第二行开始答案一定是固定的了,找不到最优解或者可能没有解
for(int op = 0; op < 32; op ++)
{
memcpy(backup, g, sizeof g); //把原始数组备份一下,然后操作g,操作完了还原,然后再操作
int step = 0; //每次遍历step都要归零
for(int i = 0; i < 5; i ++ )
{
if(op>> i & 1) // 数字2 对应了 00010 表示第2个位置的按一下
// 00010 >> 1 & 1 是1 所以turn(0, 1) 就是第一行第二个位置
// 数字3 对应了00011 表示第1 和第2个位置的按一下
//对32中情况进行遍历找到最合适(全程消耗step最少)的第一行,第一行确定了,后面行的操作也就确定了
{
step ++;
turn(0,i);
}
}
for(int i = 0; i < 4; i ++ ) //根据第一行按完之后的状态,按234行
{
for(int j = 0; j < 5; j ++ )
{
if(g[i][j] == '0')
{
step ++ ;
turn(i + 1, j); // 如果这个位置是灭的,就按下一行对应的位置
}
}
}
bool dark = false;
for(int j = 0; j < 5; j ++ )
{
if(g[4][j] == '0')
{
dark = true;
break;
}
}
if(!dark) res = min(res, step);// 对于32种情况的这一种,如果灯的全亮就记录下步数
memcpy(g, backup, sizeof backup);
}
if(res > 6) res = -1;
cout << res <<endl;
}
return 0;
}