題目描述:
有一個由按鈕組成的矩陣,其中每行有6個按鈕,共5行。每個按鈕的位置上有一盞燈。當按下一個按鈕后,該按鈕以及周圍位置(上邊、下邊、左邊、右邊)的燈都會改變一次。即,如果燈原來是點亮的,就會被熄滅;如果燈原來是熄滅的,則會被點亮。在矩陣角上的按鈕改變3盞燈的狀態;在矩陣邊上的按鈕改變4盞燈的狀態;其他的按鈕改變5盞燈的狀態。
所以在5x6的矩陣中,左邊矩陣中用X標記的按鈕表示被按下,右邊的矩陣表示燈狀態的改變。對矩陣中的每盞燈設置一個初始狀態。請你按按鈕,直至每一盞等都熄滅。與一盞燈毗鄰的多個按鈕被按下時,一個操作會抵消另一次操作的結果。在下圖中,第2行第3、5列的按鈕都被按下,因此第2行、第4列的燈的狀態就不改變。
請你寫一個程序,確定需要按下哪些按鈕,恰好使得所有的燈都熄滅。根據上面的規則,我們知道
1)第2次按下同一個按鈕時,將抵消第1次按下時所產生的結果。因此,每個按鈕最多只需要按下一次;
2)各個按鈕被按下的順序對最終的結果沒有影響;
3)對第1行中每盞點亮的燈,按下第2行對應的按鈕,就可以熄滅第1行的全部燈。如此重復下去,可以熄滅第1、2、3、4行的全部燈。同樣,按下第1、2、3、4、5列的按鈕,可以熄滅前5列的燈。
要求樣例出入,輸出所需的操作。
解題思路:
為了方便,給每個燈的位置定一個坐標,得到一個5x6的數組,但是為了避免第一行,第一列最后一列需要額外的操作,我們講數組設定為6x8的二維數組。
puzzle[i][j]表示第i行第j列上燈的初試狀態,1為亮,0為滅;
press[i][j]表示要不要按下ij位置的燈,1為按下;
如果這樣的話有2的30次方種情況,太復雜,對算法進行優化,我們發現了規律
如果位置(1,j)的燈亮,則press[2][j]的值必為1;反之亦然,所有通過操作,將第一行的燈全部熄滅,而3,4,5行不受影響,繼續后面的操作。
代碼如下:
1 #include "stdio.h" 2 3 int puzzle[6][8]; 4 int press[6][8]; 5 6 bool guess(){ 7 int i,j; 8 for(i=2;i<6;i++){ 9 for(j=1;j<7;j++){ 10 press[i][j]=(press[i-1][j]+puzzle[i-1][j]+press[i-1][j-1]+press[i-2][j]+press[i-1][j+1])%2; 11 } 12 } 13 for(j=1;j<=6;j++){ 14 if(press[5][j]!=(puzzle[5][j]+press[5][j-1]+press[5][j+1]+press[4][j])%2) 15 return false; 16 } 17 return true; 18 } 19 void process(){ 20 int c; 21 for(c=1;c<7;c++) 22 press[1][c]=0; 23 while(!guess()){ 24 press[1][1]++; 25 c=1; 26 while(press[1][c]>1){ 27 press[1][c]=0; 28 c++; 29 press[1][c]++; 30 } 31 } 32 } 33 34 int main(){ 35 int i=0,j=0; 36 for(i=0;i<6;i++) 37 puzzle[i][0]=puzzle[i][7]=press[i][0]=press[i][7]=0; 38 for(j=0;j<8;j++) 39 puzzle[0][j]=puzzle[5][j]=press[0][j]=press[5][j]=0; 40 41 for(i=1;i<6;i++) 42 for(j=1;j<7;j++) 43 scanf("%d",&puzzle[i][j]); 44 45 process(); 46 printf("press is:\n"); 47 48 for(i=1;i<6;i++){ 49 for(j=1;j<7;j++){ 50 printf("%d ",press[i][j]); 51 } 52 printf("\n"); 53 } 54 }
源碼下載(百度雲):鏈接: http://pan.baidu.com/s/1ntOqG7R 密碼: ewij