• 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;
    }
    
  • 相关阅读:
    Android中fragment之间和Activity的传值、切换
    javascript--经典实例锦集
    Android中ListView动态加载数据
    Android开发之调用系统图库及相机
    Android 相机开发详解
    RTSP实例解析
    【Android UI设计与开发】第18期:滑动菜单栏(三)SlidingMenu动画效果的实现
    js 第二小步
    JavaScript初步+基本函数
    javaweb实战开始
  • 原文地址:https://www.cnblogs.com/tomori/p/13452398.html
Copyright © 2020-2023  润新知