acwing 116. 飛行員兄弟

小程xy發表於2024-04-30

"飛行員兄弟"這個遊戲,需要玩家順利的開啟一個擁有 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;
}

覺得不錯的話, 點個贊吧~

相關文章