POJ1222熄灯问题位运算+枚举

Posted knmxx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1222熄灯问题位运算+枚举相关的知识,希望对你有一定的参考价值。

EXTENDED LIGHTS OUT
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 14231   Accepted: 8817

Description

In an extended version of the game Lights Out, is a puzzle with 5 rows of 6 buttons each (the actual puzzle has 5 rows of 5 buttons each). Each button has a light. When a button is pressed, that button and each of its (up to four) neighbors above, below, right and left, has the state of its light reversed. (If on, the light is turned off; if off, the light is turned on.) Buttons in the corners change the state of 3 buttons; buttons on an edge change the state of 4 buttons and other buttons change the state of 5. For example, if the buttons marked X on the left below were to be pressed,the display would change to the image on the right.
技术分享图片

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

The first line of the input is a positive integer n which is the number of puzzles that follow. Each puzzle will be five lines, each of which has six 0 or 1 separated by one or more spaces. A 0 indicates that the light is off, while a 1 indicates that the light is on initially.

Output

For each puzzle, the output consists of a line with the string: "PUZZLE #m", where m is the index of the puzzle in the input file. Following that line, is a puzzle-like display (in the same format as the input) . In this case, 1‘s indicate buttons that must be pressed to solve the puzzle, while 0 indicate buttons, which are not pressed. There should be exactly one space between each 0 or 1 in the output puzzle-like display.

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

有一个由按钮组成的矩阵, 其中每行有6个按钮, 共5行
每个按钮的位置上有一盏灯
当按下一个按钮后, 该按钮以及周围位置(上边, 下边, 左边, 右边)的灯都会改变状态
技术分享图片

如果灯原来是点亮的, 就会被熄灭
如果灯原来是熄灭的, 则会被点亮
? 在矩阵角上的按钮改变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熄灯问题位运算+枚举的主要内容,如果未能解决你的问题,请参考以下文章

POJ1222熄灯问题

POJ-1222EXTENDED LIGHTS OUT-位运算枚举模板

熄灯问题

POJ1753 Flip Game(位运算+暴力枚举)

POJ 1222异或高斯消元|二进制状态枚举

ACM/ICPC 之 枚举(POJ1681-画家问题+POJ1166-拨钟问题)