1813:熄灯问题

描述

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

输入

5行组成,每一行包括6个数字(0或1)。相邻两个数字之间用单个空格隔开。0表示灯的初始状态是熄灭的,1表

示灯的初始状态是点亮的。

输出

5行组成,每一行包括6个数字(0或1)。相邻两个数字之间用单个空格隔开。其中的1表示需要把对应的按钮按下,

0则表示不需要按对应的按钮。

样例输入

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

样例输出

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

来源1222

 

两种思路:

1):  枚举所有的情况:

           如:00000 00000

                 00000 00000

                 00000 00000

                 00000 00000

                 00000 00001...

         一个一个的检验。这里有一个小技巧,考虑每种情况时,一排一排的生成方案并立即检验(回溯)

         代码(WA):

    

 1 #include "stdafx.h"
 2 #include<cstdio>  
 3 #include<cstdlib>  
 4 #include<cmath>  
 5 #include<iostream>
 6 #include<algorithm>
 7 using namespace std;
 8 int set[20][10], temp[20][10], fub[20][10], way[20][10];
 9 void print()
10 {
11     for (int i = 1; i <= 5; i++)
12     {
13         for (int j = 1; j <= 6; j++)
14             cout << way[i][j] << ' ';
15         cout << endl;
16     }
17 }
18 void copy(int k,bool r)
19 {
20     if(r)
21     for (int i = k; i <= k + 2; i++)
22         for (int j = 1; j <= 6; j++)
23         {
24             fub[i][j] = temp[i][j];
25         }
26     else
27     for (int i = k; i <= k + 2; i++)
28         for (int j = 1; j <= 6; j++)
29         {
30             temp[i][j] = fub[i][j];
31         }
32 }
33 void change(int i)
34 {
35     for (int j = 1; j <= 6; j++)
36     {
37         if (way[i][j] == 1)
38         {
39             temp[i][j] = !temp[i][j];
40             temp[i + 1][j] = !temp[i + 1][j];
41             temp[i - 1][j] = !temp[i - 1][j];
42             temp[i][j + 1] = !temp[i][j + 1];
43             temp[i][j - 1] = !temp[i][j - 1];
44         }
45     }
46 }
47 bool test(int i)
48 {
49     if (i == 0) return 1;
50     for (int j = 1; j <= 6; j++)
51         if (temp[i][j] != set[i][j]) return 0;
52     return 1;
53 }
54 int fu(int i, int j)
55 {
56     if (j == 7)
57     {
58         i++; j = 1;
59     }
60     if (i >= 2 && j == 1)
61     {
62         if (i <= 6)
63         {
64             copy(i - 2, 1);
65             if (i <= 6) change(i - 1);
66             if (!test(i - 2))
67             {
68                 copy(i - 2, 0);
69                 return 0;
70             }
71         }
72         if (i == 6 && test(5) == 1)
73         {
74             print();
75             return 1;
76         }
77     }
78     if (i <= 5)
79         for (int k = 0; k <= 1; k++)
80         {
81             way[i][j] = k;
82             if (fu(i, j + 1)) return 1;
83         }
84     return 0;
85 }
86 int main()
87 {
88     for (int i = 1; i <= 5; i++)
89         for (int j = 1; j <= 6; j++)
90             cin >> set[i][j];
91     fu(1, 1);
92     return 0;
93 }

2):

       枚举 只第一排的方案 并检验,如:0 0 0 0 0 (方案)   0 1 0 1 0(状态)

                                                                      ==>   0 1 0 1 0

                           生成下一排方案:    0 1 0 1 0

                           原理是:第i排第j个登是亮的 则第i+1排第j个登是1,否则是0

                            最后检验第5排 是否全是0;

   代码如下(AC):

 1 #include "stdafx.h"
 2 #include<cstdio>  
 3 #include<cstdlib>  
 4 #include<cmath>  
 5 #include<iostream>
 6 #include<algorithm>
 7 int a[10][10], b[10][10], w[10][10];
 8 using namespace std;
 9 void doit(int i)
10 {
11     for (int j = 1; j <= 6; j++)
12         if (w[i][j] == 1)
13         {
14             a[i][j] = !a[i][j];
15             a[i + 1][j] = !a[i + 1][j];
16             a[i - 1][j] = !a[i - 1][j];
17             a[i][j + 1] = !a[i][j + 1];
18             a[i][j - 1] = !a[i][j - 1];
19         }
20 }
21 void clean()
22 {
23     for (int i = 1; i <= 5; i++)
24         for (int j = 1; j <= 6; j++)
25         {
26             a[i][j] = b[i][j];
27         }
28 }
29 bool check(int i)
30 {
31     if (i == 6)
32     {
33         for (int j = 1; j <= 6; j++)
34             if (a[5][j] == 1)
35             {
36                 clean();
37                 return 0;
38             }
39         return 1;
40     }
41     doit(i);
42     for (int j = 1; j <= 6; j++)
43     {
44         if (a[i][j] == 1) w[i + 1][j] = 1;
45         else w[i + 1][j] = 0;
46     }
47     return check(i + 1);
48 }
49 int main()
50 {
51     for (int i = 1; i <= 5; i++)
52         for (int j = 1; j <= 6; j++)
53         {
54             cin >> b[i][j];
55             a[i][j] = b[i][j];
56         }
57     for (w[1][1] = 0; w[1][1]<= 1; w[1][1]++)
58         for (w[1][2] = 0; w[1][2] <= 1; w[1][2]++)
59             for (w[1][3] = 0; w[1][3] <= 1; w[1][3]++)
60                 for (w[1][4] = 0; w[1][4] <= 1; w[1][4]++)
61                     for (w[1][5] = 0; w[1][5] <= 1; w[1][5]++)
62                         for (w[1][6] = 0; w[1][6] <= 1; w[1][6]++)
63                         {
64                             if (check(1))
65                             {
66                                 for (int i = 1; i <= 5; i++)
67                                 {
68                                     for (int j = 1; j <= 6; j++)
69                                         cout << w[i][j] << ' ';
70                                     cout << endl;
71                                 }
72                                 return 0;
73                             }
74                         }
75 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值