POJ - 1222

#include <iostream>
#include <memory>
#include <cstring>
#include <string>
using namespace std;
char oriLights[5];
char Lights[5];
char result[5];
int GetBit(char c,int i)
{ 
    return (c >> i) & 1;
}

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);//与1进行异或运算则翻转
    //与0进行异或运算则不变
}

void OutputResult(int t,char result[])
{
    cout << "PUZZLE #" << t << endl;
    for (int i = 0; i < 5;i++) {
        for (int j = 0; j < 6;j++) {
            cout << GetBit(result[i], j);
            if (j<5)
                cout << " ";
        }
        cout << endl;
    }
} 
int main()
{
    int T;
    cin >> T;
    for (int t = 1; t <= T;t++) {
        memset(oriLights, 0, sizeof(oriLights));
        for (int i = 0; i < 5;i++) {
            for (int j = 0; j < 6;j++) {
                int s;
                cin >> s;
                SetBit(oriLights[i], j, s);
            }
        }
        for (int n = 0; n < 64;n++) {
            memcpy(Lights, oriLights, sizeof(oriLights));//第i行的开关状态
            int switchs = n;
            for (int i = 0; i < 5;i++) {
                result[i] = switchs;//第i行的开关方案
                for (int j = 0; j < 6;j++) {
                    if (GetBit(switchs,j)) {//如果i行j位为真就翻转
                        if (j>0)                    
                            FlipBit(Lights[i], j-1);
                        FlipBit(Lights[i], j);
                        if(j<5)
                            FlipBit(Lights[i], j + 1);
                    }
                }
                if (i<4) {
                    Lights[i + 1] ^= switchs;//改第i+1行的灯,还是异或运算的应用
                    //如果上一行按了,势必会影响下一行
                }
                switchs = Lights[i];//为了灭掉第i行还未被灭掉的灯,所以将i+1行的开关方案设置为第i行灯亮的情况
                //1表示按下,0表示不按,1表示灯亮,0表示灯灭,正好一一对应
            }
            if (Lights[4]==0) {
                    OutputResult(t, result);
                    break;
                }
        }
    }
    getchar();
    getchar();
    return 0;
}

Lights[ i ] 是结果数组,oriLights[ i ] 是读入时的矩阵,result [ i ] 是存翻转方案的矩阵。

对这个题用的是枚举的思路,但是如果全部枚举的话就是 2 的 30 次方,所以我们只枚举第一行,就是2 的 6 次方。

因为当你的第一行按下之后,之后的四行都是要为第一行服务的,所以也就是说为了让第一行为 0 ,就要让第二行的熄灯方案

为第一行还亮着的灯的位置。

只有这样才能把之前第一行未熄灭的灯给熄灭掉,但是代码中并没有再次修改上一行灯的状态,我们只是假修改一下。

实际上并未修改,因为这样并不会影响我们继续执行下一行的熄方案,我们只是知道它已经被修改了就行了。

这样的话第二行就确定了,因此也就没有必要去枚举了。然后第三行和第四行以此类推,所以我们只需要枚举第一行。

posted @ 2018-11-06 11:08  xyee  阅读(101)  评论(0编辑  收藏  举报