• [poj]开关类问题 枚举 位运算


    poj 1222  EXTENDED LIGHTS OUT

    开关只有两种方案 按和不按,按两次相当于关

    只用枚举第一排开关的按法即可,剩下的行为使上一排的灯全部关闭,按法可以确定,并且是唯一的。

    最后检查最后一行是否都为0,都为0为可行的方案。  用位运算来实现。

    #include <iostream>
    #include <stdio.h>
    #include <cstring>
    using namespace std;
    
    char ol[5], l[5], r[5];
    int t;
    
    int getBit(char c, int i)
    {
        return 1 & (c>>i);
    }
    
    void setBit(char &c, int i, int v)
    {
        if (v) {
            c |= (1 << i);
        }
        else 
            c &= ~(1 << i);
    }
    
    void FlipBit(char &c, int i)
    {
        c ^= (1 << i);
    }
    
    void output()
    {
        cout << "PUZZLE #" << t << endl;
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 6; j++) {
                cout << getBit(r[i], j);
                if (j < 5)
                    cout << " ";
            }
            cout << endl;
        }
    }
    
    int main()
    {
        //freopen("1.txt", "r", stdin);
        int T;
        cin >> T;
        for (t = 1; t <= T; t++) {
            for (int i = 0; i < 5; i++)
                for (int j = 0; j < 6; j++) {
                    int s;
                    cin >> s;
                    setBit(ol[i], j, s);
                }
    
            for (int n = 0; n < 64; n++) {  //枚举第一列方案0~2^6-1
                memcpy(l, ol, sizeof(ol));
                int switchs = n; //当前行的开关状态
                for (int i = 0; i < 5; i++) {
                    r[i] = switchs;
                    for (int j = 0; j < 6; j++) {
                        if (getBit(switchs, j)) {
                            if (j > 0)
                                FlipBit(l[i], j-1);
                            FlipBit(l[i], j);
                            if (j < 5)
                                FlipBit(l[i], j+1);
                        }
                    }
                    if (i < 4)
                        l[i+1] ^=switchs; 
                    switchs = l[i];  //i+1行灯的状态由第i行灯的状态决定
                }
                if (l[4] == 0) {
                    output();
                    break;
                }
            }
        }
    
    
        return 0;
    }

    特殊密码锁

    描述

    有一种特殊的二进制密码锁,由n个相连的按钮组成(n<30),按钮有凹/凸两种状态,用手按按钮会改变其状态。

    然而让人头疼的是,当你按一个按钮时,跟它相邻的两个按钮状态也会反转。当然,如果你按的是最左或者最右边的按钮,该按钮只会影响到跟它相邻的一个按钮。

    当前密码锁状态已知,需要解决的问题是,你至少需要按多少次按钮,才能将密码锁转变为所期望的目标状态。

    输入两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。输出至少需要进行的按按钮操作次数,如果无法实现转变,则输出impossible。

    样例输入

    011
    000

    样例输出

    1

    类似的思想,枚举第一个的状态,两种可能,那剩下的就可以唯一确定了,最后检查最后一位即可
    #include <iostream>
    #include <stdio.h>
    #include <cstring>
    #include <string>
    using namespace std;
    #define INF 0x3f3f3f3f
    int src, des, r, t;
    int ans;
    
    int getBit(int c, int i)
    {
        return 1 & (c >> i);
    }
    
    void setBit(int &c, int i, int v)
    {
        if (v)
            c |= (1 << i);
        else
            c &= ~(1 << i);
    }
    
    void flipBit(int &c, int i)
    {
        c ^= (1 << i);
    }
    
    int main()
    {
        //freopen("1.txt", "r", stdin);
        string a;
        cin >> a;
        int len = a.length();
        for (int i = 0; i < len; i++) 
            setBit(src, i, a[i]-'0');
        
        cin >> a;
        for (int i = 0; i < len; i++)
            setBit(des, i, a[i]-'0');
    
        int Min, cnt;
        for (int p = 0; p < 2; p++) {
            Min = INF; cnt = 0;
            t = src;
            if (p) {
                flipBit(t, 0);
                flipBit(t, 1);
                cnt++;
            }
            for (int i = 1; i < len; i++) {
                if (getBit(t, i-1) != getBit(des, i-1)) {
                    cnt++;
                    flipBit(t, i);
                    if (i < len-1)
                        flipBit(t, i+1);
                }
            }
            if (getBit(t, len-1) == getBit(des, len-1)) {
                if (cnt < Min) {
                    Min = cnt;
                    ans = cnt;
                }
            }
        }
        if (Min == INF)
            cout << "impossible";
        else
            cout << ans;
    
        return 0;
    }

    poj 1166 拨钟问题

    有9个时钟,排成一个3*3的矩阵。

    |-------|    |-------|    |-------|
    | | | | | | |
    |---O | |---O | | O |
    | | | | | |
    |-------| |-------| |-------|
    A B C

    |-------| |-------| |-------|
    | | | | | |
    | O | | O | | O |
    | | | | | | | | |
    |-------| |-------| |-------|
    D E F

    |-------| |-------| |-------|
    | | | | | |
    | O | | O---| | O |
    | | | | | | | |
    |-------| |-------| |-------|
    G H I
    (图 1)

    现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。


    移动    影响的时钟

    1 ABDE
    2 ABC
    3 BCEF
    4 ADG
    5 BDEFH
    6 CFI
    7 DEGH
    8 GHI
    9 EFHI

    输入9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。输出输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。样例输入

    3 3 0 
    2 2 2 
    2 1 2 

    样例输出

    4 5 8 9 

    每个钟表有4种拨法,且与顺序无关,枚举即可 4^9种可能
    #include <iostream>
    #include <stdio.h>
    #include <cstring>
    using namespace std;
    #define INF 0x3f3f3f3f;
    int ori[4][4], s[4][4];
    int t[10];
    
    bool ok()
    {
        for (int i = 1; i <=3; i++) {
            for (int j = 1; j <=3; j++) {
                if (s[i][j])
                    return 0;
            }
        }
        return 1;
    }
    int main()
    {
        //freopen("1.txt", "r", stdin);
        for (int i = 1; i <= 3; i++)
            for (int j = 1; j <= 3; j++)
                cin >> ori[i][j];
    
        int Min = INF;
        for (int i1 = 0; i1 < 4; i1++) 
        for (int i2 = 0; i2 < 4; i2++) 
        for (int i3 = 0; i3 < 4; i3++) 
        for (int i4 = 0; i4 < 4; i4++) 
        for (int i5 = 0; i5 < 4; i5++) 
        for (int i6 = 0; i6 < 4; i6++) 
        for (int i7 = 0; i7 < 4; i7++) 
        for (int i8 = 0; i8 < 4; i8++) 
        for (int i9 = 0; i9 < 4; i9++) {
            memcpy(s, ori, sizeof(ori));   //每种枚举情况都是独立的
            s[1][1] = (s[1][1]+i1+i2+i4)%4;  //A
            s[1][2] = (s[1][2]+i1+i2+i3+i5)%4;//B
            s[1][3] = (s[1][3]+i2+i3+i6)%4;//C
            s[2][1] = (s[2][1]+i1+i4+i5+i7)%4;//D
            s[2][2] = (s[2][2]+i1+i3+i5+i7+i9)%4;//E
            s[2][3] = (s[2][3]+i3+i5+i6+i9)%4;//F
            s[3][1] = (s[3][1]+i4+i7+i8)%4;//G
            s[3][2] = (s[3][2]+i5+i7+i8+i9)%4;//H
            s[3][3] = (s[3][3]+i6+i8+i9)%4;//I
            if (ok()) {
                int tot = i1+i2+i3+i4+i5+i6+i7+i8+i9;
            //    cout << tot << endl;
                if (tot < Min) {
                    Min = tot;
                    t[1] = i1; t[2] = i2; t[3] = i3;
                    t[4] = i4; t[5] = i5; t[6] = i6;
                    t[7] = i7; t[8] = i8; t[9] = i9;
                }
            }
    
        }
        for (int i = 1; i <= 9; i++) {
            if (t[i] && i!=9) {
                for (int j = 0; j < t[i]; j++)
                    cout << i << " ";
            }
            else if (t[i] && i == 9) {
                for (int j = 0; j < t[i]-1; j++)
                    cout << i << " ";
                cout << i;
            }
        }
    
    
        return 0;
    }
    
    
  • 相关阅读:
    Python Twelfth Day
    Python Tenth Day
    Python Ninth Day
    Python Eighth Day
    Python Seventh Day
    Python Sixth Day
    Python Fifth Day
    Python Fourth Day
    Python Third Day
    金融量化分析-python量化分析系列之---使用python的tushare包获取股票历史数据和实时分笔数据
  • 原文地址:https://www.cnblogs.com/whileskies/p/7211342.html
Copyright © 2020-2023  润新知