个人陈述
由于本人是新手,所以对每一道题目的理解程度比前辈慢,速度也比前辈低。所以就需要写非常多的注释来加深我的理解,以下是我对Y总代码的深入理解版。
题目模型:
1. 由于输入元素较少,所以采用暴搜的方法。枚举所有元素个数。
2. 我们假设每个位置既是开关又是灯泡,不过开关的话就可以影响7个灯泡,所以我们需要对开关进行操作。
3. 判断保存的结果
时间复杂度(操作数):$2^{16}$ * (16 * 7 + 16 + 16) $\approx{10^7}$
其中$2^{16}$是方案数,16*7中16是开关数,7是开关一次要处理7个灯泡
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII; // 因为是两个数的格式,用Pair
const int N = 5;// 因为字符数组有一个'\0'字符
char g[N][N], backup[N][N]; // 一次方案完成后需要还原,就需要备份
int get(int x, int y)
{
return x * 4 + y;
}
void turn_one(int x, int y)
{
if (g[x][y] == '+') g[x][y] = '-';
else g[x][y] = '+';
}
void turn_all(int x, int y)
{
for (int i = 0; i < 4; i ++ )
{
turn_one(x, i); // 这个是从上到下的列变换
turn_one(i, y); // 这个是从左到右的行变换
}
turn_one(x, y); // 因为中心点,在上述变换中变了两次,要变回来
}
int main()
{
for (int i = 0; i < 4; i ++ ) cin >> g[i];
vector<PII> res; // 最终结果
// 第一步:有多少种方案就需要在最初全部用for循环枚举出来
for (int op = 0; op < 1 << 16; op ++ )
{
vector<PII> temp;
memcpy(backup, g, sizeof g); // 备份
// 第二步:进行操作
for (int i = 0; i < 4; i ++ )
for (int j = 0; j < 4; j ++ )
if (op >> get(i, j) & 1) // 因为输出结果包含具体坐标,所以我们需要编号。由于二进制的性质
{ // ,我们把开关分布转换成一行,顺序从左到右,上到下。我们假定如果是1就操作
temp.push_back({i, j}); // 将具体坐标压入临时结果中
turn_all(i, j); // 由题意,需要在按开关时变动旁边的开关。
}
// 第三步:判断所有灯泡是否全亮
bool has_closed = false;
for (int i = 0; i < 4; i ++ )
for (int j = 0; j < 4; j ++ )
if (g[i][j] == '+')
has_closed = true;
if (has_closed == false)
{
if (res.empty() || res.size() > temp.size()) res = temp; // 不要忘了第一次未操作就是空结果
}
memcpy(g, backup, sizeof g); // 还原
}
cout << res.size() << endl;
for (auto op : res) cout << op.x + 1 << ' ' << op.y + 1 << endl;
return 0;
}