【题解】AcWing 116.飞行员兄弟

AcWing 116.飞行员兄弟

题目描述

“飞行员兄弟”这个游戏,需要玩家顺利的打开一个拥有 16 16 16 个把手的冰箱。

已知每个把手可以处于以下两种状态之一:打开或关闭。

只有当所有把手都打开时,冰箱才会打开。

把手可以表示为一个 4 × 4 4×4 4×4 的矩阵,您可以改变任何一个位置 [ i , j ] [i,j] [i,j] 上把手的状态。

但是,这也会使得第 i i i 行和第 j j j 列上的所有把手的状态也随着改变。

请你求出打开冰箱所需的切换把手的次数最小值是多少。

输入格式

输入一共包含四行,每行包含四个把手的初始状态。

符号 + 表示把手处于闭合状态,而符号 - 表示把手处于打开状态。

至少一个手柄的初始状态是关闭的。

输出格式

第一行输出一个整数 N N N,表示所需的最小切换把手次数。

接下来 N N N 行描述切换顺序,每行输出两个整数,代表被切换状态的把手的行号和列号,数字之间用空格隔开。

注意:如果存在多种打开冰箱的方式,则按照优先级整体从上到下,同行从左到右打开。

数据范围

1 ≤ i , j ≤ 4 1≤i,j≤4 1i,j4

输入样例

-+--
----
----
-+--

输出样例

6
1 1
1 3
1 4
4 1
4 3
4 4

题目分析

我们枚举一个 16 16 16 位二进制数来枚举切换把手的状态,对于每一个二进制数,我们将其最终的状态表示出来,判断是否满足所有把手都打开,如果满足且步数更少,则更新答案。

需要注意的是,题目要求按照优先级输出。其实我们二进制数枚举的方法已经满足了在相同步数下,先枚举到优先级更高的方案。我们发现,按顺序枚举时,当二进制数中的 1 1 1 个数相同时,总是先有最低边的全是 1 1 1,在向这些 1 1 1 中从高位至低位添 0 0 0。譬如,我们枚举有 4 4 4 位是 1 1 1 5 5 5 位二进制数时,我们的枚举顺序是 1111 → 10111 → 11011 → 11101 → 11110 1111→10111→11011→11101→11110 111110111110111110111110,总是优先级高的先被枚举到。

代码:

#include <iostream>
#include <cstring>
using namespace std;

char m[5][5];
int map[5][5], tmp[5][5], res = 1e9, plan;

int main(){
    
    
    for (int i = 1; i <= 4; i ++)
        cin >> m[i] + 1;

    for (int i = 1; i <= 4; i ++)
        for (int j = 1; j <= 4; j ++)
            map[i][j] = m[i][j] == '+' ? 1 : 0;

    for (int i = 1; i < 1 << 16; i ++){
    
    
        bool success = 1;
        int step = 0;
        memcpy(tmp, map, sizeof(tmp));

        for (int j = 0; j < 16; j ++){
    
    
            if ((i >> j) & 1){
    
    
                step ++;
                int line = j / 4 + 1, column = j % 4 + 1;

                for (int h = 1; h <= 4; h ++)
                    tmp[h][column] ^= 1, tmp[line][h] ^= 1;
                tmp[line][column] ^= 1;
            }
        }   

        for (int h = 1; h <= 4; h ++)
            for (int j = 1; j <= 4; j ++)
                if (tmp[h][j]){
    
    
                    success = 0;
                    break;
                }

        if (success && res > step)
            res = step, plan = i;
    }

    cout << res << endl;
    for (int i = 0; i < 16; i ++)
        if ((plan >> i) & 1){
    
    
            int line = i / 4 + 1, column = i % 4 + 1;
            cout << line << " " << column << endl;
        }

    return 0;
}

Guess you like

Origin blog.csdn.net/f4u4u4r/article/details/118084600