1. 程式人生 > 其它 >AtCoder 比賽筆記(1)

AtCoder 比賽筆記(1)

Q

你玩過“拉燈”遊戲嗎?

25 盞燈排成一個 5×5 的方形。

每一個燈都有一個開關,遊戲者可以改變它的狀態。

每一步,遊戲者可以改變某一個燈的狀態。

遊戲者改變一個燈的狀態會產生連鎖反應:和這個燈上下左右相鄰的燈也要相應地改變其狀態。

我們用數字 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<n≤500
輸入樣例:
3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111

01111
11111
11111
11111
11111
輸出樣例:

3
2
-1

A

#include<iostream>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
char g[10][10];
int dx[5] = {0, -1, 0, 1, 0}, dy[5] = {0, 0, 1, 0, -1}; //origin,left,down,right,up
void turn(int x,int y){
	for(int i=0;i<5;++i){
		int a=x+dx[i],b=y+dy[i];
		if(a>=0&&a<5&&b>=0&&b<5){
			g[a][b]^=1;//48 二進位制: 110000 ,和1 異或得到 110001)得到的是49,正好是49,對應的字元是’1’.
		}
	}
}
int work () {
	int ans = INF;
	for (int k = 0; k < 1 << 5; ++k) {
		int res = 0;
		char backup[10][10];
		memcpy(backup, g, sizeof(g));
		for (int j = 0; j < 5; ++j) {
			if (k >> j & 1) {
				++res;
				turn(0, j);
			}
		}
		for (int i = 0; i < 4; ++i) {
			for (int j = 0; j < 5; ++j) {
				if ('0' == g[i][j]) {
					++res;
					turn(i + 1, j);
				}
			}
		}
		bool is_successful = true;
		for (int i = 0; i < 5; ++i) {
			if ('0' == g[4][i]) {
				is_successful = false;
				break;
			}
		}
		if (is_successful) {
			ans = min(ans, res);
		}
		memcpy(g, backup, sizeof backup);
		
		
	}
	if (ans > 6) {
		ans = -1;
	}
	return ans;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin >> T;
	while (T--) {
		for (int i = 0; i < 5; ++i) {
			cin >> g[i];
		}
		cout << work() << '\n';
	}
	return 0;
}