1. 程式人生 > 其它 >POJ 1222 EXTENDED LIGHTS OUT

POJ 1222 EXTENDED LIGHTS OUT

技術標籤:列舉列舉類演算法c++

POJ 1222 EXTENDED LIGHTS OUT

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

思路
列舉每一個位置的燈,共有30盞,需要列舉2^30,可能會超時。而題中說按下一盞燈會影響周圍4盞燈,假設我們對第一行進行操作,第一行的燈有亮著的,有暗著的。題中要求所有燈都熄滅,我們要對亮著燈進行操作,就只能通過第二行,所以第二行的操作也就確定了。同理,第三行第四行第五行的操作都已經確定了。最後我們只需要驗證第五行的燈是否熄滅。這樣總共只需要列舉第一行的燈。如果列舉完,第五行的燈都是沒有熄滅的,那就是不可能將所有燈都熄滅掉。
一個char形資料佔8個bit,我們可以使用一個char形資料來儲存一行的資料。在列舉時,我們可以不需一位一位地進行列舉,可以用一個變數i,i從0到63。比如i=0,則對應000000,i等於1對應著000001,i等於30,對應著011110。

程式碼

#include<iostream>
#include<cstring>
using namespace std;

char orilight[10];//c初始燈的狀態
char light[10];	  //過程中燈的狀態
char result[10];  //進行的操作

int getbit(char c,int i)//獲取c的第i位 
{
	return (c>>i)&1;
} 

void setbit(char&c,int i,int v)//將c的第i位設定為v
{
	if(v)		   //設定為1時 
		c|=(1<<i); //將1移動到所需變動的位置,其餘為都是0。任何數與1或運算都是1
	else 		   //設定為0時
		c&=~(1<<i);//取反將所有位的1變0,0變1,再與c進行與運算。任何數與0與運算結果都是0 	
} 

void flip(char&c,int i)//改變c的第i位
{
	c^=1<<i;   		//1^1為0,0^1為1 
} 

int main()
{
	int t;
	cin>>t;
	int cnt=1;
	while(t--)
	{
		memset(orilight,0,sizeof(orilight));
		for(int i=0;i<5;i++)				//讀入資料 
			for(int j=0;j<6;j++)
			{
				int c;
				cin>>c;
				setbit(orilight[i],j,c);
			}
		int switchs,check=0; 
		for(int i=0;i<64;i++)				//列舉64種情況 
		{
			memcpy(light,orilight,sizeof(orilight));//將初始狀態進行復制
			switchs=i;
			for(int j=0;j<5;j++)					//每一行迴圈 
			{
				result[j]=switchs;					//將進行的操作進行儲存 
				for(int k=0;k<6;k++)				//對每一位進行修改 
				{
					if(getbit(switchs,k))		    //如果進行了操作則修改 
					{
						flip(light[j],k);			//對本位進行修改 
						if(k>0)
							flip(light[j],k-1);		//對左邊進行修改 
						if(k<5)
							flip(light[j],k+1);		//對右邊進行修改	
					}	
				}
				if(j<4)
					light[j+1]^=switchs; 			//修改下一行  1^1為0,0^1為1
				switchs=light[j];					//下一行操作和此行燈的情況相同。 
			}										//如果燈是亮著的(1),則下一行需要修改(1)
			if(light[4]==0)							//如果第5行的燈都熄滅了,就退出迴圈 
			{
				check=1;
				break;
			}
		} 
		if(check)									//輸出結果 
		{
			cout<<"PUZZLE #"<<cnt<<endl;
			for(int i=0;i<5;i++)
			{
				for(int j=0;j<6;j++)
				{
					cout<<getbit(result[i],j)<<" ";
				}
				cout<<endl;
			} 
		}
		cnt++;		 
	} 
	return 0;
}