費解的開關(是否可以在6步以內將所有燈開著)
阿新 • • 發佈:2018-12-03
問題 E: 費解的開關
時間限制: 1 Sec 記憶體限制: 128 MB
題目描述
你玩過“拉燈”遊戲嗎?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
反著考慮,把所有情況都列出來就行了
/**/ #include <cstdio> #include <cstring> #include <cmath> #include <cctype> #include <iostream> #include <algorithm> #include <map> #include <set> #include <vector> #include <string> #include <stack> #include <queue> typedef long long LL; using namespace std; int t; int str; map<int, int>mp;//你想開陣列,呵呵,超空間,這就是預處理的壞處 int solve(int x, int pos){ //牛逼 x ^= (1 << pos); if(pos > 4) x ^= (1 << (pos - 5)); if(pos < 20) x ^= (1 << (pos + 5)); if(pos % 5) x ^= (1 << (pos - 1)); if(pos % 5 < 4) x ^= (1 << (pos + 1)); return x; } void init(){ str = (1 << 25) - 1; queue<int> q; q.push(str); mp[str] = 0; while(q.size()){ int t = q.front(); q.pop(); if(mp[t] == 6) return ; for (int i = 0; i < 25; i++){ int x = solve(t, i); if(!mp[x]){ mp[x] = mp[t] + 1; q.push(x); } } } } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); scanf("%d", &t); init(); while(t--){ int x = 0; char s[6][6]; for (int i = 1; i <= 5; i++) scanf("%s", s[i] + 1); for (int i = 1; i <= 5; i++){ for (int j = 1; j <= 5; j++){ x <<= 1; x += s[i][j] - '0'; } } if(x == ((1 << 25) - 1)){ printf("0\n"); }else if(mp[x]){ printf("%d\n", mp[x]); }else{ printf("-1\n"); } } return 0; } /**/