枚举:熄灯问题

题目:5行6列灯,按下开关会影响上下左右灯,求如何操作能够将灯完全熄灭?

分析如下:

1.首先我们需要枚举一个个开关下去,看灯的变化情况,但如此枚举导致量太大,故将转化思想,以局部枚举确定整体。

2.我们可以发现,当第一行开关状态确定时,后面也将会确定。举例来看:第一行开关状态确定,那么接下来,第二行开关必须将第一行灯全部熄灭,这样才有可能实现目的,故第二行开关状态也将确定。

3.故此,我们可以枚举第一行开关状态。

4.同时,在储存灯的状态时,我们可以用char类型,因为灯、开关只有2个状态,用0,1表示,那么就可用一个bit位储存,char类型一个字节,8个bit位,完全够用,但其中涉及位运算。

5.然后开关状态可用int类型表示,共2^6方种可能。

#include<iostream>
#include<cstring>
#include<memory>
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)//设置c中第i位为v当
{
    if(v)
    {
        c|=(1<<i);
    }
    else
    {
        c&=~(1<<i);//?c&=(0<<i)
    }
    
 } 
 void flipbit (char &c,int i)//将c的第i位翻转,与一亦或 
 {
     c^=(1<<i);
  }
void output(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 q=0;q<t;q++)
    {
        for(int i=0;i<5;i++)//读数 
        {    
            for(int j=0;j<6;j++)
            {
                int s;
                cin>>s;
                setbit(orilights [i],j,s);
            }
        }
        //枚举
        int n;
        for(n=0;n<64;n++)
        {
            int switchs=n;
            memcpy(lights,orilights,sizeof(orilights));
            for(int i=0;i<5;i++)
            {    result[i]=switchs;
                for(int j=0;j<6;j++)
                {
                    if(Getbit(switchs,j))
                    {
                        flipbit(lights[i],j);
                        if(j>0)
                        flipbit(lights[i],j-1);
                        if(j<5)
                        flipbit(lights[i],j+1);
                    }
                    
                }
                if(i<4)
                lights[i+1]^=switchs;
                switchs=lights[i];
            }
            if(lights[4]==0)
            {
                output(q,result);
                break;
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值