AcWing 116. 飞行员兄弟
原题链接
简单
超详细!!!
方法:总共有16个格子,对操作方式进行遍历(用二进制数表示操作),1对应该给位置要改变状态,0对应不做任何操作
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef pair<int, int> p; // 临时存储坐标
const int N = 5;
char map[N][N], backup[N][N]; // 冰箱状态和备份数组
int get_potition(int x, int y) {
return 4 * x + y;
}
bool success() { // 最后判断是否所以开关都是打开的
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
if (map[i][j] == '+')
return false;
return true;
}
void turn_one(int i, int j) {
if (map[i][j] == '+')
map[i][j] = '-';
else
map [i][j] = '+';
}
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 >> map[i];
vector<p> res; // 表示最终最小步数的结果,因为有多种操作,所以
// 我们必须再来个同类型的临时动态数组
// 循环2^16种操作
for (int op = 0; op < 1 << 16; op++) {
// op代表16个二进制数字,1表示改变状态,0表示不变
memcpy(backup, map, sizeof map); // 把原始状态备份到backup中去
vector<p> temp; // 临时存储操作坐标
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
if (op >> get_potition(i, j) & 1) { // 右移0-15位把操作的每一位都枚举一遍,看该位是否需要操作
// 存储坐标
temp.push_back({i, j}); // {i,j}表示 pair类型
turn_all(i, j);
}
}
if (success()) { // 如果全部'-' 即成功的操作
if (res.empty() || res.size() > temp.size())
res = temp;
break; // 每种状态只有唯一的方案(操作方式)
}
memcpy(map, backup, sizeof map); // 恢复原始状态
}
cout << res.size() << endl;
for (auto k : res)
cout << k.first + 1 << ' ' << k.second + 1 << endl;
return 0;
}