遞歸與遞推-------------------費解的開關

你玩過“拉燈”遊戲嗎?25盞燈排成一個5x5的方形。每一個燈都有一個開關,遊戲者可以改變它的狀態。每一步,遊戲者可以改變某一個燈的狀態。遊戲者改變一個燈的狀態會產生連鎖反應:和這個燈上下左右相鄰的燈也要相應地改變其狀態。
我們用數字“1”表示一盞開着的燈,用數字“0”表示關着的燈。下面這種狀態
10111
01101
10111
10000
11011

在改變了最左上角的燈的狀態後將變成:
01111
11101
10111
10000
11011

再改變它正中間的燈後狀態將變成:
01111
11001
11001
10100
11011

給定一些遊戲的初始狀態,編寫程序判斷遊戲者是否可能在6步以內使所有的燈都變亮。
輸入格式
第一行輸入正整數nn,代表數據中共有nn個待解決的遊戲初始狀態。
以下若干行數據分爲nn組,每組數據有5行,每行5個字符。每組數據描述了一個遊戲的初始狀態。各組數據間用一個空行分隔。
輸出格式
一共輸出nn行數據,每行有一個小於等於6的整數,它表示對於輸入數據中對應的遊戲狀態最少需要幾步才能使所有燈變亮。
對於某一個遊戲初始狀態,若6步以內無法使所有燈變亮,則輸出“-1”。
數據範圍
0<n≤5000<n≤500
輸入樣例:
3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111

01111
11111
11111
11111
11111

輸出樣例:
3
2
-1

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstring>
using namespace std;
const int N = 6;
char g[N][N], backup[N][N];
int dx[5] = {0, -1, 0, 1, 0}, dy[5] = {0, 0, 1, 0, -1};
void turn(int x, int y){
 for (int u = 0; u < 5; u ++){
  int a = x + dx[u], b = y + dy[u];
  if (a < 0 || b < 0 || a >= 5 || b >= 5)   continue;
  g[a][b] ^= 1;
 }
}
int main(){
 int T;
 cin >> T;
 while(T --){
  for (int i = 0; i < 5; i ++)   scanf("%s", g[i]);
    int res = 10;
  for (int op = 0; op < 1 << 5; op ++){
   memcpy(backup, g, sizeof g);
   int step = 0;
   for (int i = 0; i < 5; i ++){
    if (op >> i & 1){
     step ++;
     turn(0, i);
    }
   }
   for (int i = 0; i < 4; i ++)
    for (int j = 0; j < 5; j ++){
     if (g[i][j] == '0'){
      turn(i + 1, j);
      step ++;
     }
   }
     bool dark = false;
    for (int i = 0; i < 5; i ++)
     if (g[4][i] == '0'){
      dark = true;
      break;
     } 
   if (!dark)  res = min(res, step);
   memcpy(g, backup, sizeof g);
  }
    if (res > 6)   res = -1;
  cout << res << endl;
 }
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章