算法设计 熄灯问题

题目描述:

  有一个由按钮组成的矩阵,其中每行有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

posted @ 2015-10-21 14:24  SeeKHit  阅读(4004)  评论(0编辑  收藏  举报