链接:116. 飞行员兄弟 - AcWing题库
跟它上面的那道费解的开关差不多(好像还更简单一点),二进制枚举每一种情况,找出满足条件的最小操作次数就好了。
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
#define N 2000005
#define M 1331
#define PII pair<int,int>
#define PIII pair<pair<int,int>,int>
#define VPII vector<PII>
#define VPIII vector<PIII>
#define inf 0x3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
const double eps = 1e-6;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define mod 1000000007
char str[5][5], sty[5][5];
VPII ans;
//转变第i行和第j列
void turn(int i, int j) {
if (sty[i][j] == '+') sty[i][j] = '-';
else sty[i][j] = '+';
}
//转变sty[i][j]
void turnall(int i, int j) {
for (int k = 1; k <= 4; k++) turn(k, j),turn(i,k);
turn(i, j);
}
//获取i,j在16位进制数的第几位
int getij(int i, int j) {
return 4 * (i - 1) + j-1;
}
void solve() {
//读入
for (int i = 1; i <= 4; i++)
{
for (int j = 1; j <= 4; j++) {
cin >> str[i][j];
}
}
//将四行排在一行,16个位置可看作长度16位的二进制数,从0到1<<16-1,就相当于枚举了每一种点法
(例如0000 0000 0000 0001就相当于只按了str[1][1],其余都不改动),每次取最优解即可得到答案。
for (int p = 0; p < (1 << 16); p++) {
//res存储此次所改变的点
VPII res;
//将str拷贝给sty,然后每次枚举改变sty
memcpy(sty, str, sizeof str);
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
//判断p该位置是否为1,若为1,则进行操作
if ((p >> getij(i, j)) & 1) {
turnall(i, j);
res.push_back({ i,j });
}
}
}
//检验是否满足条件
bool tr = false;
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
if (sty[i][j]=='+') {
tr = true;
break;
}
}
}
if (!tr) {
if (ans.size() == 0) ans = res;
else if (ans.size() > res.size()) ans = res;
}
}
//输出答案
cout << ans.size() << "\n";
for (auto it : ans)cout << it.first << " " << it.second << "\n";
}
int main() {
solve();
return 0;
}