"飛行員兄弟"這個遊戲,需要玩家順利的開啟一個擁有 16 個把手的冰箱。
已知每個把手可以處於以下兩種狀態之一:開啟或關閉。
只有當所有把手都開啟時,冰箱才會開啟。
把手可以表示為一個 4×4 的矩陣,您可以改變任何一個位置 [i,j] 上把手的狀態。
但是,這也會使得第 i 行和第 j 列上的所有把手的狀態也隨著改變。
請你求出開啟冰箱所需的切換把手的次數最小值是多少。
輸入格式
輸入一共包含四行,每行包含四個把手的初始狀態。
符號 + 表示把手處於閉合狀態,而符號 - 表示把手處於開啟狀態。
至少一個手柄的初始狀態是關閉的。
輸出格式
第一行輸出一個整數 N,表示所需的最小切換把手次數。
接下來 N 行描述切換順序,每行輸出兩個整數,代表被切換狀態的把手的行號和列號,數字之間用空格隔開。
注意:如果存在多種開啟冰箱的方式,則按照優先順序整體從上到下,同行從左到右開啟。
資料範圍
1≤i,j≤4
輸入樣例:
-+--
----
----
-+--
輸出樣例:
6
1 1
1 3
1 4
4 1
4 3
4 4
題解
- 列舉所有可能, 也就是說 16 個開關都有兩種可能, 開啟或者關閉
- 用二進位制表示所有可能, [0, 2^16)
- 二進位制位 為 1 的表示操作這個開關, 即 把這個開關和同一行同一列的開關的狀態都取反
#include <bits/stdc++.h>
using namespace std;
const int N = 4;
char g[N][N], back[N][N];
void change(int x, int y)
{
for (int j = 0; j < N; j ++) g[x][j] = (g[x][j] == '+'?'-':'+');
for (int i = 0; i < N; i ++) g[i][y] = (g[i][y] == '+'?'-':'+');
g[x][y] = (g[x][y] == '+'?'-':'+');
}
int main()
{
for (int i = 0; i < N; i ++) cin >> g[i];
int ed = pow(2, N * N);
vector<pair<int,int>> res; // 儲存答案
int mnstep = 0x3f3f3f3f;
memcpy(back, g, sizeof g); // 備份, 列舉每種可能的時候會改變 g
for (int op = 0; op < ed; op ++) // [0, 2^16)
{
vector<pair<int,int>> path; // 操作路徑
int step = 0; // 記錄操作步數
memcpy(g, back, sizeof back); // 初始化原圖 g
for (int i = 0; i < N * N; i ++)
{
int x = i / N, y = i % N; // 把二進位制的位置 轉換成 對應的座標
if (op >> i & 1)
{
change(x, y);
step++;
path.push_back({x + 1, y + 1}); // 題中輸出的下表是從 1-4, 我們儲存的時候是 0-3
}
}
bool f = true;
for (int i = 0; i < N; i ++)
for (int j = 0; j < N; j ++)
if (g[i][j] == '+')
{
f = false; // 判斷是否把所有開關都開啟了
break;
}
if (f && step < mnstep)
{
mnstep = step;
res = path; // 操作次數少的話 把少的路徑賦值給 res
}
}
cout << mnstep << endl;
for (int i = 0; i < res.size(); i ++)
cout << res[i].first << ' ' << res[i].second << endl;
return 0;
}
覺得不錯的話, 點個贊吧~