枚举算法——熄灯问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了枚举算法——熄灯问题相关的知识,希望对你有一定的参考价值。

枚举法练习:

题目:

有 一个由按钮组成的矩阵,其中每行有6个按钮,共5行。每个按钮的位置上有一盏灯。当按下一个按钮后,该按钮以及周围位置(上边、下边、左边、右边)的灯都 会改变一次。即,如果灯原来是点亮的,就会被熄灭;如果灯原来是熄灭的,则会被点亮。在矩阵角上的按钮改变3盏灯的状态;在矩阵边上的按钮改变4盏灯的状 态;其他的按钮改变5盏灯的状态。

技术分享

在 上图中,左边矩阵中用X标记的按钮表示被按下,右边的矩阵表示灯状态的改变。对矩阵中的每盏灯设置一个初始状态。请你按按钮,直至每一盏等都熄灭。与一盏 灯毗邻的多个按钮被按下时,一个操作会抵消另一次操作的结果。在下图中,第2行第3、5列的按钮都被按下,因此第2行、第4列的灯的状态就不改变。

技术分享

请 你写一个程序,确定需要按下哪些按钮,恰好使得所有的灯都熄灭。根据上面的规则,我们知道1)第2次按下同一个按钮时,将抵消第1次按下时所产生的结果。 因此,每个按钮最多只需要按下一次;2)各个按钮被按下的顺序对最终的结果没有影响;3)对第1行中每盏点亮的灯,按下第2行对应的按钮,就可以熄灭第1 行的全部灯。如此重复下去,可以熄灭第1、2、3、4行的全部灯。同样,按下第1、2、3、4、5列的按钮,可以熄灭前5列的灯。


输入
第一行是一个正整数N,表示需要解决的案例数。每个案例由5行组成,每一行包括6个数字。这些数字以空格隔开,可以是0或1。0表示灯的初始状态是熄灭的,1表示灯的初始状态是点亮的。
输出
对每个案例,首先输出一行,输出字符串“PUZZLE #m”,其中m是该案例的序号。接着按照该案例的输入格式输出5行,其中的1表示需要把对应的按钮按下,0则表示不需要按对应的按钮。每个数字以一个空格隔开。
样例输入:
2 
0 1 1 0 1 0
1 0 0 1 1 1 
0 0 1 0 0 1 
1 0 0 1 0 1 
0 1 1 1 0 0 
0 0 1 0 1 0 
1 0 1 0 1 1 
0 0 1 0 1 1 
1 0 1 1 0 0 
0 1 0 1 0 0 

 

样例输出:
PUZZLE #1 
1 0 1 0 0 1 
1 1 0 1 0 1 
0 0 1 0 1 1 
1 0 0 1 0 0 
0 1 0 0 0 0
PUZZLE #2 
1 0 0 1 1 1 
1 1 0 0 0 0 
0 0 0 1 0 0 
1 1 0 1 0 1 
1 0 1 1 0 1 

 

 1 //程序实现
 2 #include<iostream>
 3 using namespace std;
 4 int puzzle[6][8], press[6][8];//puzzle数组表示灯的亮灭状态,1表示亮,0表示灭
 5                                     //press数组表示:“是否需要点亮或熄灭指定位置的灯”,1表示是,0表示否
 6 bool guess();//声明guess函数
 7 void enumeration();//声明enumeration函数
 8 int main() {
 9     int n;
10     cin >> n;
11     if (n == 0)
12         cout << "error!" << endl;
13     //该段程序可有可无
14     /*    for (int i = 0; i < 6; i++)
15         {
16             press[i][0] = 0;
17             press[i][7] = 0;
18             puzzle[i][0] = 0;
19         }
20         for (int i = 0; i < 8; i++)
21         {
22             press[0][i] = 0;
23             puzzle[0][i] = 0;
24         }*/
25     for (int i = 0; i < n; i++)
26     {
27         for (int r = 1; r < 6; r++)
28             for (int c = 1; c < 7; c++)
29             {
30                 cin >> puzzle[r][c];
31             }
32 
33         //调用函数
34         enumeration();
35         cout << "PUZZLE#" << i+1 << endl;
36         for (int r = 1; r < 6; r++)
37         {
38             for (int c = 1; c < 7; c++)
39             {
40                 cout << press[r][c] << " ";
41             }
42             cout << endl;
43         }
44     }
45 }
46 //判断函数
47 bool guess()
48 {
49     for (int r = 1; r < 5; r++)
50         for (int c = 1; c < 7; c++)
51             press[r + 1][c] = (puzzle[r][c] + press[r][c] +
52                 press[r][c + 1] + press[r][c - 1] + press[r - 1][c]) % 2;
53     
54     for (int c = 1; c < 7; c++)
55         if (puzzle[5][c] != (press[5][c] + press[5][c + 1] +
56             press[5][c - 1] + press[4][c]) % 2)
57         {
58             return false;
59         }
60             
61     return true;
62 }
63 //枚举函数
64 void enumeration() 
65 {
66     int c;
67     for ( c = 0; c < c; c++)
68     {
69         press[1][c] = 0;
70     }
71     while (guess() == false)
72     {
73         press[1][1]++;
74         c = 1;
75         while (press[1][c]>1) 
76         {
77             press[1][c] = 0;
78             c++;
79             press[1][c]++;
80         }
81     }
82 }

 



 
 
 
 
 

以上是关于枚举算法——熄灯问题的主要内容,如果未能解决你的问题,请参考以下文章

枚举2--熄灯问题

枚举_百炼 2811 熄灯问题 (美妙的枚举函数)

POJ1222熄灯问题位运算+枚举

枚举 - bailian 2811:熄灯问题

POJ1222熄灯问题

用树枝和界限熄灯