2130 - 枚举-熄灯问题

2130 - 枚举-熄灯问题

c++刷题 超能力编程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(题解都在代码里)

f1:

/*
* POJ1222:
题解:
    思路:
    每个按钮只需按下一次
    按钮按键的顺序可以随意
    枚举第一行状态

    实现:
    观察到只有0,1,可以使用一维char类型对于灯初始状态以及灯操作存储。
    枚举第一列,可以通过2的六次方的二进制进行状态存储,位运算获取。

*/

#include <memory>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;


int Get_bit(char c, int i)
{
    return (c >> i) & 1;
}
//与操作取值,取字符c的第i个bit,也就是01矩阵中的一个元素

void Set_bit(char &c ,int i,int v)
{
    if (v)
    {
        c|= (1 << i);
        //将第i列的数据与1或运算,也即将那一行赋为1
    }
    else
    {
        c &= ~(1 << i);
        //A &= ~B是给B中为1的位对应于A的同样位上置0(单片机中的操作)
    }
}
//设置字符c第i位为v

void FlipBit(char& c, int i)
{
    c ^= (1 << i);
}
//翻转第i位的值
//异或:参加运算的两个对象,如果两个位为“异”(值不同),则该位结果为1,否则为0

void Output_result(int t, char result[])
{
    cout << "PUZZLE#" << t << endl;
    for (int i = 0; i < 5 ; ++i)
    {
        for (int j = 0; j < 6; ++j)
        {
            cout << Get_bit(result[i], j);
            if (j < 5)
            {
                cout<<"  ";
            }    
        }
        cout << endl;
    }
}
//输出整个矩阵,也就是所有的按键按下的方法

int main()
{

    char g_ori_Lights[5];
    char g_lights[5];
    char g_result[5];
    char switches;
    int T;
    cin >> T;
    for (int t = 1; t < T + 1; ++t)
    {
        memset(g_ori_Lights, 0, sizeof(g_ori_Lights));
        for (int i = 0; i < 5; ++i)
        {
            for (int j = 0; j < 6; ++j)
            {
                int s;
                cin >> s;
                Set_bit(g_ori_Lights[i], j, s);
            }
        }
        //读入所有的初始开关数矩阵

        for (int n = 0; n < 64; ++n)
        {
            
            memcpy(g_lights, g_ori_Lights, sizeof(g_ori_Lights));
            switches = n;
            //ori_lights初始化g_lights

            for (int i = 0; i < 5; ++i)
            {
                //此循环处理第i行
                g_result[i] = switches;
                for (int j = 0; j < 6; j++)
                {
                    //此循环处理第i行j列开关
                    if (Get_bit(switches, j))
                    {
                        if (j > 0)
                        {
                            FlipBit(g_lights[i], j - 1);
                            //翻转j的左边一位(已经判断左边存在数字)
                        }
                        FlipBit(g_lights[i], j);
                        //翻转j
                        if (j < 5)
                        {
                            FlipBit(g_lights[i], j + 1);
                            //翻转j的右边一位(已经判断右边存在数字
                        }
                    }

                }

                if (i < 4)
                {

                    g_lights[i + 1] ^= switches;
                    /*
                       ***处理第i+1行的那一个灯的翻转***
                       switchs假设的是第一行的翻转后状态,一共有64种
                       对于第二行,应该将第一行中没有变暗的位置进行操作
                       异或操作,则与1异或(亮的灯调暗)翻转,与0异或(暗的灯不管)不会翻转
                    */

                    switches = g_lights[i];
                }
            }
        if (g_lights[4] == 0)
        {
                Output_result(t, g_result);
                break;
        }
            
        }
        
        
    
    }
    return 0;
}

f2:

#include<iostream>
#include<string.h>
using namespace std;
char orilight[5];//记录原始灯的情况 ,一共五行,每行用一个char字符表示原始灯的状态
char changelight[5];//灯的变化情况
char  result[5];//最终开关方案
int T;//测试案例个数
void setBit(char &c,int i,int v)//设置c的第i位为v
{
    if(v)
    {
        c |= (1<<i);//设为1
    }
    else
        c &= ~(1<<i);//设为0 ,~:取反
}
int getBit(char c,int i)//获得c的第i位
{
    int t = (c>>i) & 1;//右移i位后和1与
    return t;
}
void flipBit(char &c,int i)//对c的第i位取反
{
    c ^= (1<<i);//翻转某一位:与1异或
}
int main()
{
    cin >> T;
    for(int x = 1;x<=T;++x)
    {
        //输入测试数据
        for(int i = 0;i<5;++i)
            for(int j = 0;j<6;++j)
            {
                int t;
                cin >> t;
                setBit(orilight[i],j,t);
             }
         
        for(int n = 0;n<64;++n)
        {
            memcpy(changelight,orilight,sizeof(orilight));//每测试一种情况前都需要先把原始灯复制到改变灯数组里,调试改变灯数组里的 情况
            int switchs = n;
            for(int i = 0;i<5;++i)
            {
                result[i] = switchs;
                for(int j = 0;j<6;++j)
                {
                    int r = getBit(switchs,j);
                     
                    if(r)
                    {
                        if(j>0)
                            flipBit(changelight[i],j-1);
                        flipBit(changelight[i],j);
                        if(j<5)
                            flipBit(changelight[i],j+1);
 
                    }
                     
                }
                if(i<4)//把i+1正下面那个灯取反
                    changelight[i+1] ^= result[i];
                switchs = changelight[i];//下一行的开关等于这一行亮的灯
                 
            }
            if(changelight[4]==0)//如果第五行灯全熄灭了,说明这次方案是正确的
            {
                cout << "PUZZLE #"<<x<<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;
                    }
                break;
            }
        }
         
    }
    return 0;
 }
  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值