POJ1222熄灯问题位运算+枚举
Posted knmxx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1222熄灯问题位运算+枚举相关的知识,希望对你有一定的参考价值。
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 14231 | Accepted: 8817 |
Description
The aim of the game is, starting from any initial set of lights on in the display, to press buttons to get the display to a state where all lights are off. When adjacent buttons are pressed, the action of one button can undo the effect of another. For instance, in the display below, pressing buttons marked X in the left display results in the right display.Note that the buttons in row 2 column 3 and row 2 column 5 both change the state of the button in row 2 column 4,so that, in the end, its state is unchanged.
Note:
1. It does not matter what order the buttons are pressed.
2. If a button is pressed a second time, it exactly cancels the effect of the first press, so no button ever need be pressed more than once.
3. As illustrated in the second diagram, all the lights in the first row may be turned off, by pressing the corresponding buttons in the second row. By repeating this process in each row, all the lights in the first
four rows may be turned out. Similarly, by pressing buttons in columns 2, 3 ?, all lights in the first 5 columns may be turned off.
Write a program to solve the puzzle.
Input
Output
Sample Input
2 0 1 1 0 1 0 1 0 0 1 1 1 0 0 1 0 0 1 1 0 0 1 0 1 0 1 1 1 0 0 0 0 1 0 1 0 1 0 1 0 1 1 0 0 1 0 1 1 1 0 1 1 0 0 0 1 0 1 0 0
Sample Output
PUZZLE #1 1 0 1 0 0 1 1 1 0 1 0 1 0 0 1 0 1 1 1 0 0 1 0 0 0 1 0 0 0 0 PUZZLE #2 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 0 0 1 1 0 1 0 1 1 0 1 1 0 1
Source
– 每个按钮的位置上有一盏灯
– 当按下一个按钮后, 该按钮以及周围位置(上边, 下边, 左边, 右边)的灯都会改变状态
– 如果灯原来是点亮的, 就会被熄灭
– 如果灯原来是熄灭的, 则会被点亮
? 在矩阵角上的按钮改变3盏灯的状态
? 在矩阵边上的按钮改变4盏灯的状态
? 其他的按钮改变5盏灯的状态
? 与一盏灯毗邻的多个按钮被按下时,一个操作会抵消另一次操作的结果
? 给定矩阵中每盏灯的初始状态,求一种按按钮方案,使得所有的灯都熄灭
输入:
– 第一行是一个正整数N, 表示需要解决的案例数
– 每个案例由5行组成, 每一行包括6个数字
– 这些数字以空格隔开, 可以是0或1
– 0 表示灯的初始状态是熄灭的
– 1 表示灯的初始状态是点亮的
输出:
– 对每个案例, 首先输出一行,
输出字符串 “PUZZLE #m”, 其中m是该案例的序号
– 接着按照该案例的输入格式输出5行
? 1 表示需要把对应的按钮按下
? 0 表示不需要按对应的按钮
? 每个数字以一个空格隔开
思路:
如何减少内存:这题灯一共五行六列,char占一个字节也就是有8位,可以用一位表示一列,所以每一行用一个char字符就能保存一行灯或开关的状态了,开一个char[5]就能保存所有灯或开关的状态了。
如何减少枚举次数:不用每行每列都枚举一遍,可以只枚举第一行开关所有的情况,共有2的6次方=64种,第一行的开关确定,剩下每一行的开关也就确定了。原因是因为题目要求是每个灯都要熄灭,
如果第一行的开关按完后,只会影响第一行和第二行,假设第一行还有未熄灭的灯,那么第二行的开关肯定就是要熄灭第一行的灯,依次类推,所以我们只需要枚举第一行的情况,最后看看按照第一行开关的按法,第五行的灯是不是全熄灭了就行。
#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; }
以上是关于POJ1222熄灯问题位运算+枚举的主要内容,如果未能解决你的问题,请参考以下文章