枚舉-OpenJudge-1222-熄燈問題

1222:熄燈問題

題目描述

有一個由按鈕組成的矩陣,其中每行有6個按鈕,共5行。每個按鈕的位置上有一盞燈。當按下一個按鈕後,該按鈕以及周圍位置(上邊、下邊、左邊、右邊)的燈都會改變一次。即,如果燈原來是點亮的,就會被熄滅;如果燈原來是熄滅的,則會被點亮。在矩陣角上的按鈕改變3盞燈的狀態;在矩陣邊上的按鈕改變4盞燈的狀態;其他的按鈕改變5盞燈的狀態。

這裏寫圖片描述

在上圖中,左邊矩陣中用X標記的按鈕表示被按下,右邊的矩陣表示燈狀態的改變。對矩陣中的每盞燈設置一個初始狀態。請你按按鈕,直至每一盞等都熄滅。與一盞燈毗鄰的多個按鈕被按下時,一個操作會抵消另一次操作的結果。在下圖中,第2行第3、5列的按鈕都被按下,因此第2行、第4列的燈的狀態就不改變。

這裏寫圖片描述

請你寫一個程序,確定需要按下哪些按鈕,恰好使得所有的燈都熄滅。根據上面的規則,我們知道1)第2次按下同一個按鈕時,將抵消第1次按下時所產生的結果。因此,每個按鈕最多只需要按下一次;2)各個按鈕被按下的順序對最終的結果沒有影響;3)對第1行中每盞點亮的燈,按下第2行對應的按鈕,就可以熄滅第1行的全部燈。如此重複下去,可以熄滅第1、2、3、4行的全部燈。同樣,按下第1、2、3、4、5列的按鈕,可以熄滅前5列的燈。

輸入

5行組成,每一行包括6個數字(0或1)。相鄰兩個數字之間用單個空格隔開。0表示燈的初始狀態是熄滅的,1表示燈的初始狀態是點亮的。

輸出

5行組成,每一行包括6個數字(0或1)。相鄰兩個數字之間用單個空格隔開。其中的1表示需要把對應的按鈕按下,0則表示不需要按對應的按鈕。

樣例輸入

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

樣例輸出

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
解題思路
1、閱題後通過提示信息可知當按下一個按鈕後,該按鈕以及周圍位置(上邊、下邊、左邊、右邊)的燈都會改變一次。即,如果燈原來是點亮的,就會被熄滅;如果燈原來是熄滅的,則會被點亮。②第2次按下同一個按鈕時,將抵消第1次按下時所產生的結果。因此,每個按鈕最多只需要按下一次。③各個按鈕被按下的順序對最終的結果沒有影響。④對第1行中每盞點亮的燈,按下第2行對應的按鈕,就可以熄滅第1行的全部燈。如此重複下去,可以熄滅第1、2、3、4行的全部燈。同樣,按下第1、2、3、4、5列的按鈕,可以熄滅前5列的燈。
2、我們發現燈只有按下與不按下兩種情況。若我們要知道哪些燈需要按下哪些燈不需要按可以實現燈全部熄滅
這樣測試最大可以達到2^30次,這樣的測試無疑是費時的,我們應選擇採用更合理的方式來減少測試量。
3、通過題幹中提示④我們可以發現,每當有一行需要按下的燈確定後他下一行需要按下的燈也隨之可以被確定,由此我們可以得出,每當第一行的燈被確定後,所有燈將均會被確定。這樣我們便將原本需要的測試量2^30減小爲2^6。
4、接下來我們應該思考用什麼來表示這些燈的滅與亮?首先我們可以想到的是用一個二維數組進行存儲,但這裏我較爲推薦的是用char類型的一維數組來存儲,因爲用char類型的一維數組不僅在空間上,而且在運行時間上,到比使用二維數據更優。每一個char類型的字符均是由8位二進制數組成的,這樣我們便可以使用位運算來改變其0和1的值。

5、這裏就涉及到如何將這些01串轉入char類型的數組中,我們應該設計一個函數。

char oriLights[6] = { 0 };           //oriLights[]應設置在main函數外面,方便使用 


for (int i = 0; i < 5; i++)              
{
	for (int j = 5; j >= 0; j--)
	{
		int s;
		cin >> s;
		Set(&oriLights[i], j, s);
	}
}

void Set(char *c, int i, int s)           
{
	*c |= (s << i);
}
如此便可以將每一行的01串寫入每一個char類型的字符中。
6、接着需要遍歷第一行按下與不按下的所有情況(2^6),這時我們一個新建一個char類型的數組存儲oriLights[]裏面的所有值。(若不採取這一種方式,在執行完第一次判斷後oriLights[]裏面的值就會被改變,無法進行重新判斷)
char result[6] = {0};                            //結果,寫下燈是否按下 
char G[6] = {0};								 //複製oriLights的數組 

for(char temp = 0; temp < 64; temp++)             
{
	for(int i = 0; i < 6; i++)
	{
		G[i] = oriLights[i];
		result[i] = 0;
	}
	result[0] = temp;
} 
7、再來便可以依照提示④的方式對新數組進行更改。
8、在執行完第五行後,遍歷整個新數組,檢查是否值全爲0,若是則打印出按下方式後return,若不是則返回循環重新判斷。
下面是源代碼:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char oriLights[6] = { 0 };								//oriLights[]應設置在main函數外面,方便使用
char result[6] = {0}; 									//結果,寫下燈是否按下 
char G[6] = {0};										//複製oriLights的數組 
void Set(char *c, int i, int s)							//錄入每一個位的燈滅情況		
{
	*c |= (s << i);
}

void switchs(char *c)									//對測試下燈滅情況進行修改 
{
	for(int i = 5; i >= 0; i--)
	{
		char temp = (1 << i);
		char Temp = temp & *c;
		if(Temp > 0)
		{
			G[0] ^=Temp;
			G[1] ^=Temp;
			if(i == 5)
			{
				G[0] ^= (Temp >> 1);
			}
			else if(i == 0)
			{
				G[0] ^= (Temp << 1);
			}
			else
			{
				G[0] ^= (Temp >> 1);
				G[0] ^= (Temp << 1);
			}
		}
	}
}

void change(int i, int j) 								//按提示4修改燈滅情況 
{
	char temp = G[i-1] & (1 << j);
	result[i] |= temp;

	if(temp > 0)
	{
		G[i-1] ^= temp;
		G[i+1] ^= temp;
		G[i] ^= temp;
		if(j == 5)
		{
			G[i] ^= (temp >> 1);
		}
		else if(j == 0)
		{
			G[i] ^= (temp << 1);
		}
		else
		{
			G[i] ^= (temp >> 1);
			G[i] ^= (temp << 1);
		}
	}
}

void input(char *c)											//輸出結果 
{
	for(int i = 5; i >= 0; i--)
	{
		char temp = *c & (1 << i);
		if(temp > 0)
		{
			cout << "1 ";
		}
		else
		{
			cout << "0 ";
		}
	}
}
int main()
{

		for(int i = 0; i < 5; i++)
		{
			oriLights[i] = 0;
		}
		for (int i = 0; i < 5; i++)
		{
			for (int j = 5; j >= 0; j--)
			{
				int s;
				cin >> s;
				Set(&oriLights[i], j, s);
			}
		}
		for(char temp = 0; temp < 64; temp++)
		{
			for(int i = 0; i < 6; i++)
			{
				G[i] = oriLights[i];
				result[i] = 0;
			}
			result[0] = temp;
			switchs(&temp);

			for(int i = 1; i < 5; i++)
			{
				for(int j = 5; j >= 0; j--)
				{
					change(i, j);
				}
			
			}
			int nums = 0;								//判斷最後每個字符的ASCLL碼的值是否爲0,若是nums+1,當nums==5時表示在該情況下燈全滅 
			for(int i = 0; i < 5; i++)
			{
				if(G[i] == 0)
				{
					
					nums++;
				}
			}
			if(nums==5)
			{
				for(int i = 0; i < 5; i++)
				{
					input(&result[i]);
					cout << endl;
				}
			}
		}

	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章