遞推 - 費解的開關

遞推 - 費解的開關

題目:

你玩過“拉燈”遊戲嗎?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”。

數據範圍:

0<n5000<n≤500

輸入樣例:

3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111


01111
11111
11111
11111
11111

輸出樣例:

3
2
-1

分析:

容易發現,只要第一行確定以後,剩下的四行也隨之確定。

01因爲當第一行確定後,第一行的'0'僅能由第二行的開關去改變,當第一行全部被第二行變成'1'後,第二行也隨之確定。

以此類推,即每一行均由下一行來改變。

0使1若經過一些列操作後,最後一行仍然存在'0',說明無法使得方陣變成全'1'狀態。否則就更新操作次數。

61最終,若操作次數超過6,輸出-1,否則輸出次數。

注意:

由於第一行的每種起始狀態都唯一確定一種可能的方案,因此我們需要枚舉第一行的所有可能起始狀態。

51用一個5位二進制數來枚舉,若某位上爲'1',就在輸入的第一行的狀態基礎上進行一次操作,同時要計下操作次數。

011010ASCII4801ASCII49110110另外,將'0'變成'1','1'變成'0'可以通過與1異或來完成。\\因爲'0'的ASCII碼是48,二進制表示下的最後一位是0,\\ 而'1'的ASCII碼是49,二進制表示下的最後一位是1。與1異或就能達到0變1,1變0的效果。

代碼:

#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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章