1. 程式人生 > >費解的開關(狀壓)

費解的開關(狀壓)

輸出數據 pre nbsp 中間 times 解決 har col 可能

題目描述

你玩過“拉燈”遊戲嗎?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個字符。每組數據描述了一個遊戲的初始狀態。各組數據間用一個空行分隔。
對於30%的數據,n<=5;
對於100%的數據,n<=500。

輸出

輸出數據一共有n行,每行有一個小於等於6的整數,它表示對於輸入數據中對應的遊戲狀態最少需要幾步才能使所有燈變亮。
對於某一個遊戲初始狀態,若6步以內無法使所有燈變亮,請輸出“-1”。

樣例輸入

3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111

01111
11111
11111
11111
11111

樣例輸出

3
2
-1 


在圖確定的情況下,確定第i行的點擊方案,第i+1行的點擊方案也隨之確定。所以狀壓枚舉第一行所有點擊方案,共2? 32種;

一、用0x3f3f3f3f表示maxn;
二、用二進制的01表示狀態;

#include <bits/stdc++.h>

using
namespace std; const int maxn = 5; const int inf = 0x3f3f3f3f; char _map[maxn][maxn + 5]; char sta[maxn][maxn + 5]; int times, min_times; int dx[5] = {-1, 0, 0, 1}; int dy[5] = {0, 1, -1, 0}; bool check(int x, int y) { if (x >= 0 && x < 5 && y >= 0 && y < 5) return
1; else return 0; } void press(int x, int y) { sta[x][y] = (sta[x][y] == 0) ? 1 : 0; for (int i = 0; i < 4; i++) { if (check(x + dx[i], y + dy[i])) sta[x + dx[i]][y + dy[i]] = (sta[x + dx[i]][y + dy[i]] == 0) ? 1 : 0; } times++; } int main() { int n; cin >> n; while (n--) { min_times = inf; for (int i = 0; i < maxn; i++) cin >> _map[i]; for (int i = 0; i < (1 << maxn); i++) { times=0; memcpy(sta, _map, sizeof(_map)); int now = i; for (int j = 0; now; j++, now >>= 1) { if (now & 1) press(0, j); } for (int j = 1; j < maxn; ++j) { for (int k = 0; k < maxn; ++k) { if (sta[j - 1][k] == 0) press(j, k); } } int flag = 1; for (int j = 0; j < maxn; j++) { for (int k = 0; k < maxn; ++k) { if (sta[j][k] == 0) flag = 0; } } if (flag) min_times = min(times, min_times); } if (min_times > 6) cout << -1 << endl; else cout << min_times << endl; //cout<<min_times<<endl; } return 0; }

費解的開關(狀壓)