1. 程式人生 > 實用技巧 >js - 解決微信環境下,ios軟鍵盤收起後頁面空白

js - 解決微信環境下,ios軟鍵盤收起後頁面空白

題目描述

你玩過“拉燈”遊戲嗎?25盞燈排成一個5x5的方形。每一個燈都有一個開關,遊戲者可以改變它的狀態。每一步,遊戲者可以改變某一個燈的狀態。遊戲者改變一個燈的狀態會產生連鎖反應:和這個燈上下左右相鄰的燈也要相應地改變其狀態。

我們用數字“1”表示一盞開著的燈,用數字“0”表示關著的燈。下面這種狀態

10111
01101
10111
10000
11011

在改變了最左上角的燈的狀態後將變成:

01111
11101
10111
10000
11011

再改變它正中間的燈後狀態將變成:

01111
11001
11001
10100
11011

給定一些遊戲的初始狀態,編寫程式判斷遊戲者是否可能在6步以內使所有的燈都變亮。

輸入格式

第一行輸入正整數n,代表資料中共有n個待解決的遊戲初始狀態。

以下若干行資料分為n組,每組資料有5行,每行5個字元。每組資料描述了一個遊戲的初始狀態。各組資料間用一個空行分隔。

輸出格式

一共輸出n行資料,每行有一個小於等於6的整數,它表示對於輸入資料中對應的遊戲狀態最少需要幾步才能使所有燈變亮。

對於某一個遊戲初始狀態,若6步以內無法使所有燈變亮,則輸出“-1”。

資料範圍

0\(\leq\) n \(\leq\) 500

輸入樣例

3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111

01111
11111
11111
11111
11111

輸出樣例

3
2
-1

思路

我們先假定第一行的開關不被按,這樣的話要使第一行的某個關著的燈開啟,應當按下其同一列中下一行的燈。當穩定好第1行的燈後,要想保持第一行的燈的狀態不再被改變,第2行的燈也不能再按下了。如果想要使第2行的相應的關著的燈開啟,我們需要按下第3行中同列相應的燈。剩下的行數依次類推。到第n行時,為了使第n-1行的燈的狀態不再被改變我們不能再按下第n行的燈。這樣,判斷此時所有的燈是否全部是開啟的狀態的話我們只需要判斷第n行的燈的狀態是否全部是開啟的狀態。因為我們已經保證了第1~n-1行的燈全部是開啟的狀態。

而實際上,第一行的燈也是可以按的,根據每個燈按與不按的選擇。我們共有\(2^5\)

=32種方案。當按完第一行的燈後我們再來考慮上面的思路就可以了。跟據之前學的狀態壓縮的知識,我們可以使用列舉變數k的2進製表示形式中的1/0來記錄第1行中相應位置的燈的按/不按
eg:k=23=\({(10111)}_2\)——>按/按/按/不按/按(注意:k的二進位制形式是從右往左開始計算的)

C++程式碼

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
char mp[7][7];
int dx[5] = { 0,0,-1,1,0 }, dy[5] = { 1,-1,0,0,0 };//方位陣列
void turn(int x, int y)//使座標(x,y)周圍的燈的狀態改變
{
	for (int i = 0;i < 5;i++)
	{
		int a = x + dx[i];
		int b = y + dy[i];
		if (a >= 0 && a < 5 && b >= 0 && b < 5)
			mp[a][b] = '0' + '1' - mp[a][b];//使滿足條件的燈的狀態改變
	}
}
int work()
{
	int res = INF;
	for (int k = 0;k < (1 << 5);k++)//第0行中共有5個燈,每個燈都有按與不按兩種選擇,對應於k的2進製表示就是每位上的1/0。所以最後共有32種情況。我們將第一行所有按的情況都列舉一下,在第一行確定的情況下,剩下的行數,按與不按也就可以確定了
	{
		char re[7][7];
		int ans = 0;
		memcpy(re, mp, sizeof (mp));//把mp中的資訊拷貝到re中
		for (int i = 0;i < 5;i++)
			if (k >> i & 1)
			{
				ans++;
				turn(0, i);//根據k的2進製表示資訊我們可以知道需要將(0,i)上的燈按一下
			}
		for (int i = 0;i < 4;i++)
		{
			for (int j = 0;j < 5;j++)
				if (mp[i][j] == '0')
				{
					ans++;
					turn(i + 1, j);
				}
		}
		bool is_sucessful = true;//判斷最後一行的燈是不是全部都是亮的,如果是的話就表示我們列舉的這個方案是成功的
		for (int i = 0;i < 5;i++)
			if (mp[4][i] == '0')
			{
				is_sucessful = false;
				break;
			}
		if (is_sucessful)//如果該方案成功的話我們需要維護一下最小值便於最後輸出方案最小值
			res = min(res, ans);
		memcpy(mp, re, sizeof (mp));//再把mp中燈的開關情況恢復,便於接下來對k的列舉
	}
	if(res>6)
	   res=-1;
	return res;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	while (n--)
	{
		for (int i = 0;i < 5;i++)
		{
			for (int j = 0;j < 5;j++)
				cin >> mp[i][j];
		}
		cout << work() << endl;
	}
	return 0;
}