题目链接
思路
开关问题关键点:
- 操作顺序是无所谓的
- 每一个开关只能操作一次,因为都是操作两遍等于没有操作
而且
2
16
2^{16}
216 并不大,可以枚举每一种操作方法,取最小数
用枚举二进制数,代替dfs找所有组合方案。
不理解的点:为什么顺序一定是无所谓的,有没有可能利用别的一块操作,再做这块操作更好的这种情况呢?有懂的看到可以教一下吗,谢谢!
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 10;
char g[N][N];
char backup[N][N];
int ans = 0x3f3f3f3f;
vector<pair<int, int>> v;
int get(int x, int y)
{
return x * 4 + y;
}
void turn (int x, int y)
{
int dx = x;
int dy = y;
if (g[dx][dy] == '-') g[dx][dy] = '+';
else g[dx][dy] = '-';
dx = x;
dy = y;
while (1)
{
dx = dx - 1;
dy = dy;
if (dx < 0 || dx >= 4 || dy < 0 || dy >= 4)
{
break;
}
if (g[dx][dy] == '-') g[dx][dy] = '+';
else g[dx][dy] = '-';
}
dx = x;
dy = y;
while (1)
{
dx = dx + 1;
dy = dy;
if (dx < 0 || dx >= 4 || dy < 0 || dy >= 4)
{
break;
}
if (g[dx][dy] == '-') g[dx][dy] = '+';
else g[dx][dy] = '-';
}
dx = x;
dy = y;
while (1)
{
dx = dx ;
dy = dy - 1;
if (dx < 0 || dx >= 4 || dy < 0 || dy >= 4)
{
break;
}
if (g[dx][dy] == '-') g[dx][dy] = '+';
else g[dx][dy] = '-';
}
dx = x;
dy = y;
while (1)
{
dx = dx ;
dy = dy + 1;
if (dx < 0 || dx >= 4 || dy < 0 || dy >= 4)
{
break;
}
if (g[dx][dy] == '-') g[dx][dy] = '+';
else g[dx][dy] = '-';
}
}
int main()
{
// 输入状态
for (int i = 0; i < 4; i ++ ) cin >> g[i];
// 便利每一种操作方式,1左移16位得到最小的17位2进制数,用<号相当于取到最大的16位,是[0, 17)
for (int op = 0; op < 1 << 16; op ++ )
{
// 用来存每一步的操作
vector<pair<int, int>> p1;
// 备份一下初始状态
memcpy(backup, g, sizeof g);
int num = 0;
//这里采用遍历坐标的方法,访问每一位
for (int i = 0; i < 4; i ++ )
{
for (int j = 0; j < 4; j ++ )
{
int x = get(i, j); //得到该坐标在16位数中是第几位
if (op >> x & 1 == 1) //看看这一位要不要操作
{
turn(i, j); //进行操作
num ++;//增加步数
p1.push_back({i, j}); //添加操作记录
}
}
}
// 判断是否全是减号
int f = 0;
for (int i = 0; i < 4; i ++ )
{
for (int j = 0; j < 4; j ++ )
{
if (g[i][j] == '+')
{
f = 1;
break;
}
}
}
if (!f)
{
if (num <= ans)
{
v = p1;
ans = num;
}
}
// 恢复到初始化前的状态
memcpy(g, backup, sizeof backup);
}
cout << ans << endl;
for (auto i : v)
{
cout << i.first + 1 << " " << i.second + 1 << endl;
}
return 0;
}