116. 飞行员兄弟

开关问题满足的条件:

  1. 最优解情况下,一个开关只按一次
  2. 开关的顺序无关

由于数据范围比较小,可以直接枚举出所有开关情况(0~2^16 - 1),然后操作一下灯泡,然后检查一下是不是全开开了即可,注意最后答案要求字典序最小的步数最少的解。

之所以从0~2^16枚举是因为后面一个数中包含的1的个数一定>= 前面一个数的1的个数,所以从小到大找到的第一个解就是答案。

暴力代码

#include<iostream>
#include<vector>
#include<cstring>

using namespace std;

#define PII pair<int, int>

const int N = 10;

char g[N][N], backup[N][N];

void turn(int x, int y){
    g[x][y] ^= 6;
    for(int i = 0; i < 4; i ++){
        g[x][i] ^= 6;
        g[i][y] ^= 6;
    }
}

int check(){
    for(int i = 0; i < 4; i ++)
        for(int j = 0; j < 4; j ++)
            if(g[i][j] == '+') return 0;
            
    return 1;
}

int main(){
    for(int i = 0; i < 4; i ++) cin >> g[i];
    
    vector<PII> path;

    memcpy(backup, g, sizeof g);
    
    for(int i = (1 << 16) - 1; i >= 0; i --){
        for(int j = 0; j < 16; j ++){
            if((i >> j & 1) == 0){
                turn(j / 4, j % 4);
                path.push_back({j / 4, j % 4});
            }
        }
        
        if(check())
            break;

        memcpy(g, backup, sizeof g);
        path.clear();
    }
    
    cout << path.size() << endl;
    for(auto t : path) cout << t.first + 1 << ' ' << t.second + 1 << endl;
    
    return 0;
}

位运算

优化成1维。

#include<iostream>
#include<vector>
#include<cstring>

using namespace std;

const int N = 10;

#define PII pair<int, int>

int g[N], backup[N];

void turn(int x, int y){
    int d = 1 << (3 - y);
    g[x] ^= d;
    for(int i = 0; i < 4; i ++) g[i] ^= d;
    g[x] ^= (1 << 4) - 1;
}

int check(){
    for(int i = 0; i < 4; i ++)
        if(g[i]) return 0;
    
    return 1;
}

int main(){
    for(int i = 0; i < 4; i ++){
        for(int j = 0; j < 4; j ++){
            char c = getchar();
            g[i] = g[i] * 2 + (c == '+');
        }
        getchar();
    }
    
    vector<PII> path;
    
    memcpy(backup, g, sizeof g);
    
    for(int i = 0; i < 1 << 16; i ++){
        for(int j = 0; j < 16; j ++){
            if(i >> j & 1){
                turn(j / 4, j % 4);
                path.push_back({j / 4, j % 4});
            }
        }
        
        if(check()) break;
        path.clear();
        memcpy(g, backup, sizeof g);
    }
    
    cout << path.size() << endl;
    for(auto t : path) cout << t.first + 1 << ' ' << t.second + 1 << endl;
}
posted @ 2020-08-07 13:50  yys_c  阅读(130)  评论(0编辑  收藏  举报