遞推 - 費解的開關
題目:
你玩過“拉燈”遊戲嗎?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”。
數據範圍:
輸入樣例:
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
輸出樣例:
3
2
-1
分析:
注意:
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=6;
char g[N][N],bg[N][N];
int dir[5][2]={{0,0},{1,0},{-1,0},{0,1},{0,-1}};
void turn(int x,int y)
{
for(int i=0;i<5;i++)
{
int a=x+dir[i][0],b=y+dir[i][1];
if(a<0||a>4||b<0||b>4) continue;
g[a][b]^=1;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int res=10;
for(int i=0;i<5;i++) scanf("%s",bg[i]);
for(int op=0;op<32;op++)
{
memcpy(g,bg,sizeof g);
int cnt=0;
for(int i=0;i<5;i++)
if(op>>i&1)
{
cnt++;
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);
cnt++;
}
bool flag=true;
for(int i=0;i<5;i++)
if(g[4][i]=='0')
{
flag=false;
break;
}
if(flag) res=min(res,cnt);
}
if(res>6) res=-1;
printf("%d\n",res);
}
return 0;
}