您的位置:首页 > 大数据 > 人工智能

熄灯问题 BailianPOJ 2811 或者 BailianPOJ 1222

2018-03-28 21:42 260 查看

熄灯问题 BailianPOJ 2811 或者 BailianPOJ 1222

标签(空格分隔): 算法 算法竞赛

题目有些长,就不写了,在北大百炼平台上有,1222是英文版题,2811是中文版。这道题我听的郭炜老师的课,做的真心巧妙,用的也是出乎意料。具体解题思路在下面的代码里,是老师的源程序,我手动敲的。其中有很多个地方不好懂,统一分析在代码最后。

#include <memory>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
char oriLights[5];  //存放原始输入的灯矩阵,每个字符表示一行
char lights[5];     //变化中的灯的矩阵
char result[5];     //最终的开关结果

int GetBit(char c,int i)    //返回某一行的第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);
}
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++)  {           //对每一次测试用例
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)  {   //按开关的方式,因为一共6个数,每盏灯有2种状态,则一共有64种状态
int switchs = n;
memcpy(lights,oriLights,sizeof(oriLights));     //将原始灯开关数组复制一份到lights,在其中做接下来的操作
for (int i=0;i<5;++i)   {       //对每一行灯执行操作
result[i]=switchs;          //将我们的开关方法输入字符型数据中,以二进制形式存储。等到条件妈满足,作为结果输出
for (int j=0;j<6;j++)   {   //对每一行上的每一盏灯
if (GetBit(switchs,j))  {       //获取这一种操作时,第j位上灯的状况。如果它亮着,就执行下面的模拟,将它“按灭”
if (j>0)                    //j>0,就将它的前一位反转
FlipBit(lights[i],j-1);
FlipBit(lights[i],j);       //一定会执行的操作,将第j位反转
if (j<5)
FlipBit(lights[i],j+1); //j<5,就将它的后一位反转
}
}
if (i<4)            //数组未超限时,对i+1组数组进行操作,表示按了第i行的灯后对i+1行的影响。一个异或就行了,很神奇。
lights[i+1]^=switchs;
switchs = lights[i];        //显然,按掉初始时的亮灯后,形成第i行灯亮灭的序列。此时对i行操作已完成,我们要想熄灭第i行剩余灯,就必须在第i+1行按同样位置的灯。
}
if (lights[4]==0)   {       //如果遍历到此处,最后一行的灯都为0,也就是全灭时,就输出result。
OutPutResult(t,result);
break;
}
}
}
return 0;
}


难点:

字符型数据存储布尔值。由于一个字符型数据只占1字节,1字节=8 bit,最大存2^8=256,所以用它可以直接存储少量布尔值数据,正好可以表示这里灯的亮灭。如果将整型数据赋给字符型,字符型的比特位会表示这个整型数的二进制形式。比如下面一段代码,输入一个小于256的正整数,就能输出它在字符型数据中的存储情况。

#include <iostream>
#include <algorithm>
using namespac
4000
e std;
int GetBit(char a,int i);
int main()  {
int n;
scanf("%d",&n);
char a;
a=n;
for (int i=7;i>=0;i--)  {
printf("%d",GetBit(a,i));
if (i!=0)   cout << " ";
}
cout << endl;
return 0;
}

int GetBit(char a,int i)    {
return (a>>i)&1;
}


其中用到了位运算的知识,忘了的只能自行百度了,我也是这样现学的。

2. 位运算。其中数次用到了位运算,用来处理二进制数很方便,很快捷。如果不熟练,最好多做一些习题来巩固一下。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: