zoukankan      html  css  js  c++  java
  • poj 1222 (枚举)

    试题连接:http://poj.org/problem?id=1222

          先想到的是枚举,可是30个开关如果直接枚举的话,2^(30)肯定超时,那么看是否能找到一个局部, 当这个局部被确定后,剩余其他部分状态只能是确定的一种。
          经过观察会发现,第1行就是这样一个局部,即第1行开关一旦确定,其余几行开关状态也会确定。(因为第一行开关作用以后,还会有几盏灯未熄灭,这时就需要下一行对应位置的开关按下,来熄灭上一行未熄灭的灯,如此往复,直到最后一行,如果最后一行灯正好全部熄灭,则该方案可行,否则不可行。

          这里用位运算,可以更加简便。每一行只有6个灯,且状态都是用 0,1表示,而char 有8个bite,所以一个char 类型就可以表示一个灯的状态,(将6个灯的状态存在char类型的6个bite里面)。用长度为5的char型数组就可以装下灯的状态。

           第一行6个灯,共有2^(6)=64种开关状态,而从  0~2^(6)-1  这64个数中的每一数的二进制 都可以表示开关的一个0 1组合
           即从 00000000~11111111,
    ---------------------------------------------------------------------------------------------------
          关于位运算可以先复习一下:http://blog.csdn.net/morewindows/article/details/7354571

         基本的位操作符有与、或、异或、取反、左移、右移这6种,它们的运算规则如下所示:

    符号

     描述

     运算规则                        by MoreWindows

    &      

     与

    两个位都为1时,结果才为1

    |  

     或    

    两个位都为0时,结果才为0

    ^    

    异或

    两个位相同为0,相异为1

    ~   

    取反

    0变1,1变0

    << 

    左移

    各二进位全部左移若干位,高位丢弃,低位补0

    >> 

    右移

    各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

         特别强调:0^其他,不变;1^其他,逆置

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    char orlight[5];  //灯原始状态
    char light[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);    //0^(异或)其他,不变,1^(异或)其他,逆置
    }
    
    void OutputResult(int t,char result[]) //输出结果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=0; t<T; t++)
        {
            //读取灯的状态
            for(int i=0; i<5; i++)
            {
                for(int j=0; j<6; j++)
                {
                    int s;
                    cin>>s;
                    SetBit(orlight[i],j,s); //设置第i行,第j列的灯的状态
                }
            }
    
            for(int n=0; n<64; n++)
            {
                int switchs=n;  //switchs 是0~63的整数,用其二进制数 表示灯的情况!!!
    
                //将 orlight数组拷贝到 light数组中,对灯的操作全在light中进行
                memcpy(light,orlight,sizeof(orlight));
    
                for(int i=0; i<5; i++)
                {
                    result[i]=switchs;
                    for(int j=0; j<6; j++)
                    {
                        if(GetBit(switchs,j))
                        {
                            FlipBit(light[i],j);
                            if(j>0)  //如果开关左边有灯,则将其左边翻转
                                FlipBit(light[i],j-1);
                            if(j<5)  //如果开关右边有灯,则将其左边翻转
                                FlipBit(light[i],j+1);
                        }
    
                    }
                    if(i<4)
                        light[i+1]^=switchs;  //下一行会受到上一行开关的影响
    
                    switchs=light[i];   //更新下一行的开关状态,其状态取决于上一行那些灯亮了
                }
    
                if(light[4]==0)
                {//如果最后一行灯全熄灭,则输出
                    OutputResult(t+1,result);
                }
    
            }
        }
        return 0;
    }
    


  • 相关阅读:
    指向const的指针和const指针
    c++类中的静态成员
    Vue.js图片预览插件
    vue 报错 Cannot read property '__ob__' of undefined的解决方法
    vue/webpack的一些小技巧
    css强制html不换行 css强制英文单词断行 重拾丢失的
    js将 HTML 页面生成 PDF 并下载
    Vue跨路由触发事件,Vue监听sessionStorage
    ssh 上传文件以及文件夹到linux服务器
    【原创】移动端获取用户公网ip,获取用户ip
  • 原文地址:https://www.cnblogs.com/zhanyeye/p/9746112.html
Copyright © 2011-2022 走看看