題意:
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輸入樣例:
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
輸出樣例:
3
2-1
思路:
分析發現兩個性質:
1.每乙個位置最多改變一次狀態。因為如果操作兩次的話,相當於不操作,必然是不滿足最優解。
2.在一套方案中,操作的順序無關緊要。
so,如果我們確定了第1行的操作方案,後面的行數都可以依此遞推。
具體方法如下:
列舉第1行的2^5種狀態,
通過對第i+1行(的每一位)進行操作,來使第i行的燈全亮,這樣使前4行的燈全亮,(每一行開關的操作 被 前一行燈的亮滅狀態 所唯一確定)
最後判斷第5行的燈是否全亮且操作步驟在6步以內。
總結一下:
第1行燈的狀態(32種)決定了第1行的操作,
第1行燈的狀態決定了第2行的操作(操作第2行使第1行全亮),第2行的狀態決定了第3行的操作,第3行的狀態決定了第4行的操作,
最後判斷第5行是不是全亮。
**:
#includeusing namespace std;
const int n=6;
char g[n][n],backup[n][n];
int dx=,dy=;
void turn(int x,int y)
}}int main()
}for(int i=0;i<4;++i)}}
bool dark=false;
for(int j=0;j<5;++j)
}if(!dark) res=min(res,step);
memcpy(g,backup,sizeof backup);
}if(res>6) puts("-1");
else cout<注意:
1. if(op>>j&1)我一開始寫的是if( (op>>j&1) != g[0][j]-'0'),也ac了,後者的意思是,將[0,32)運算元的二進位制裡的1和0對應到g[0][j]的『1』和『0』,對第1行進行操作,使第1行的燈的狀態變成和運算元op的二進位制一樣。其實不必。運算元op的二進位制裡的1,就表示這一位的燈應該改變狀態,就可以了。
2.(char) '0' = (int) 48 = 110000b
(char) '1' = (int) 49 = 110001b
所以char型『0』和『1』之間改變狀態只需要異或1就可以了。
翻硬幣(遞推)
飛行員兄弟(暴力列舉)
演算法 費解的開關(遞推與遞迴)
這題類似於我們玩過的乙個小遊戲。當按下中間按鈕時,這個按鈕及上下左右四個方向上的燈的開關轉換一次。本題要求我們將整個矩陣能否在6步以內點亮。其實這個題的思路很 清奇 因為當我們將第一行的所有操作進行遍歷 共有2 5種情況 然後為了將第一行的燈全部點亮,故第二行的操作就能根據第一行燈的狀態唯一確定。以...
AcWing 95 費解的開關(遞推)
題目 include include include include using namespace std const int n 6 char g n n backup n n backup用於儲存,複製原陣列 int dx 5 dy 5 用於方位轉化 void turn int x,int y...
遞推 AcWing 95 費解的開關
思路 列舉第一行的所有情況 列舉完第一行後,固定住第一行,此時第二行按哪個按鈕是確定的。假設第一行某盞燈是0,那麼需要按第二行對應的燈泡來改變第一行。同理,操作第三行和第四行 遍歷第五行看看是否都為1。如果都為1,則達到目標。include include using namespace std c...