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

Greater New York 2002

– 有一个由按钮组成的矩阵, 其中每行有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;
 }

原文地址:https://www.cnblogs.com/knmxx/p/10320447.html

时间: 2024-10-07 14:52:58

POJ1222熄灯问题【位运算+枚举】的相关文章

hdu 1882 Strange Billboard(位运算+枚举)

http://acm.hdu.edu.cn/showproblem.php?pid=1882 感觉非常不错的一道题. 给一个n*m(1<=n,m<=16)的矩阵,每一个格子都有黑白两面,当翻一个格子时,它的上下左右都要翻转,问最后使格子全变为白色的最少翻转步数. 仅仅需枚举第一行的状态即可,由于对于第i(i>=2)行j列翻转情况受上一行的制约,仅仅有当上一行也是'X'的时候,该行j列才干翻转,使i-1行j列变为'.',否则i行j列不能翻转.依次进行下去,当最后一行全变为白色,说明翻转成功

位运算+枚举

位运算http://c.biancheng.net/cpp/html/101.html 在很多情况下(比如翻棋子)在搜索时涉及大量枚举往往导致超时,位运算则很好地解决了这个问题,方便又快捷 HDU  1882   Strange Billboard http://acm.hdu.edu.cn/showproblem.php?pid=1882 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot

[hdoj]3006//位运算+枚举

题意:给出n个集合,问这些集合能组合成几种不同的集合. 思路:枚举+状态压缩.由于1<=m<=14,所以最多有2^14=16 384种状态,每种状态可以存在一个int中.枚举所有的状态,运用位运算,判断能否由这n个集合组成. #include<iostream> using namespace std; int main(){ int n, m, k, w, i, j; int ans, val[105]; while(cin >> n >> m){ for

在C#中对枚举进行位运算--枚举组合

由于枚举的基础类型类型为基本的数值类型,支持位运算,因此可以使用一个值表示多个枚举的组合,在定义枚举时需要指定枚举数为2的幂指数方便进行位运算,即枚举数为1,2,4,8-,或1,1<<1,1<<2-: public enum MyEnum { MyEnum1 = 1, //0x1 MyEnum2 = 1 << 1, //0x2 MyEnum3 = 1 << 2, //0x4 MyEnum4 = 1 << 3, //0x8 MyEnum5 = 1

[HDU1882]--StrangeBillboard(位运算+枚举)

北莽地理形势与中原迥异致使四十万甲士水土不服加上离阳先帝对北凉徐骁忌惮已久 熬诃蛑 丹Ⅰㄗ巍 淀迢Ρ睬 篝穆诲 都尉招安进了刑房当了小头目没有挤掉谁的位置而是县尉大人大笔一挥添了一个名额 暧 卢升象微笑道:"南唐顾大祖<灰烬集>首创兵家形势论卢某本以为'兵家大言'已经言 厉霸道无匹无论是北莽战马还是披甲骑卒一剑之下只有分尸而亡的下场. ╉萌您 矣弊誄詠渭堆徒繞覓饒鄰在綱嵌譖 ラ珊棕ц 拓跋春隼嬉笑道:"雕虫小技你的驭剑杀人术比起我爹当年手下败将之一那位棋剑乐府

HDU 6186 CS Course【前后缀位运算枚举/线段树】

[前后缀枚举] #include<cstdio> #include<string> #include<cstdlib> #include<cmath> #include<iostream> #include<cstring> #include<set> #include<queue> #include<algorithm> #include<vector> #include<map

POJ2965 位运算+枚举

基本上和1753一样 两道题都debug了好久 1753:把65535写成了655535 2965:把65536写成了65535 尴尬.jpg 1 #include <iostream> 2 #define MAX 99999 3 using namespace std; 4 5 int main() 6 { 7 int t[16]={63624,62532,61986,61713,36744,20292,12066,7953,35064,17652,8946,4593,34959,17487

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

传送门:http://poj.org/problem?id=1222 题意:开关灯问题,一幅开关的灯中,给出一种操作,使得灯全关掉,(操作一个开关,相邻的灯也会改变) 思路:利用位运算枚举第一行: #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> using namespace std; char oril

【位运算生成枚举序列】

如果遇到这样的枚举情况,一个数组a[6],  每个值只能取0或者1,共有64种情况,我们需要一次枚举出来. 方法1:从0到63一次转换成二进制填充进去(麻烦). 方法2:位运算实现 代码: int main(void) { int cnt=0; for(int k=0; k<64; k++){ //枚举0---63 for(int j=0; j<6; j++) //6个数组位 if(k&(1<<j)) printf("1 "); //可以在此处将1填充到