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;
}