看了y总的蓝桥杯,再加深一下印象。
题意
给你一个5*5的矩阵有25盏灯,你需要把所有的灯都打开,如果你要改变一个灯的状态那么这个灯上下左右的状态都会被改变,如果能在6操作内把所有的灯打开,请输出最小操作数,否咋输出-1。
思路
首先每个灯最多改变一次状态。
如果我们固定第一行的状态,那么我们可以得出每一行开关的操作完全被前一行灯的亮灭状态决定。
如果第一行进行操作过后是10110那么第二行的第1,3,4列是不能操作了,一旦操作对应的第一行的灯就会关闭,操作就冗余了。
所以我们只需要枚举第一行的所有操作,然后依次往下递推就是了,第一行一共就有 2 5 = 32 2^5 = 32 25=32种,可以采取dfs,或者二进制枚举来。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long
#define endl "\n"
using namespace std;
const int N = 10;
const int dx[] = {-1, 0, 1, 0, 0};
const int dy[] = { 0, 1, 0, -1, 0};
int n, m, k, _;
char arr[N][N], backup[N][N];
int res;
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;
arr[a][b] ^= 1;
}
}
void solve()
{
//枚举第一行的操作。
//每一行开关的操作完全被前一行灯的亮灭状态决定。
res = 10;
for (int i = 0; i < 5; ++i) cin >> arr[i];
for (int op = 0; op < 32; ++op)
{
memcpy(backup, arr, sizeof backup);
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 (arr[i][j] == '0')
{
step++;
turn(i + 1, j);
}
}
bool f = 1;
for (int i = 0; i < 5; i++)
{
if (arr[4][i] == '0')
{
f = 0;
break;
}
}
if (f) res = min(res, step);
memcpy(arr, backup, sizeof arr);
}
if (res > 6) res = -1;
cout << res << endl;
}
signed main()
{
IOS;
cin >> _;
while (_--)
solve();
return 0;
}```