算法篇【枚举4 -- 熄灯问题】

1、问题:有一个由按钮组成的矩阵,其中每行6个按钮,共5行,每个按钮的位置对应一盏灯,按下一个按钮后,上下左右的灯的状态就会翻转。

输入:

         第一行是一个正整数N,表示需要解决的案例数

         每个案例由5行组成,每一行包括6个数字,这些数字以空格相间,是0或者1。

输出:

         对于每个案例,首先输出一行字符串“PUZZLE  #m”,其中m是该案例的序号,

         接着按照案例的输入格式输出5行,1表示按钮按下,0表示不需要按下按钮,以空格相间。

思路:

         对第一行中的每盏灯,按下第二行对应的按钮,就可以将第一行的灯全部熄灭,

         如此这样按照1-5行的顺序,重复下去,就可以将1,2,3,4行全部按灭,如果此时第5行的灯也是灭的,那么就是问题的解,否则,这种按法不是想要的解。

         上面没有成功的话,则需要重新从第一行开始按,第一行的按法总共有2*5=32,所以在第一行的局部按法之上,总共可以进行32次尝试,得到问题的解。

 

 1 #include <iostream>
 2 #include <string>
 3 #include <cstring>
 4 #include <memory>
 5 using namespace std;
 6 
 7 int GetBit(char c, int i){
 8     //取c的第i位
 9     return (c >> i) & 1 ; 
10 }
11 
12 void SetBit(char & c, int i, int v){
13     //设置c的第i位为v 
14     if(v){
15         c |= (1 << i);
16     }
17     else{
18         c &= ~(1 << i);
19     }
20 }
21 
22 void Flip(char & c, int i){
23     //将c的第i位取反
24     c ^= (1 << i);
25 }
26 
27 void OutputResult(int t, char result[]){
28     cout << "PUZZLE # " << t << endl;
29     for(int i = 0; i < 5; i++){
30         for(int j = 0; j < 6; j++){
31             cout << GetBit(result[i],j) ;
32             if(j < 5){
33                 cout << " " ;
34             }
35         }
36         cout << endl ;
37     }
38 }
39  
40 int main()
41 {
42     char oriLights[5] ;
43     char lights[5] ;
44     char result[5] ;
45     char switchs   ;
46     int T ;
47     cout<<"The results num = " << endl;
48     cin >> T ;
49     for(int t=1; t <= T; t++){
50         memset(oriLights,0,sizeof(oriLights));
51         for(int i = 0; i < 5; i++){
52             cout <<"Please Input the lights[j]"<<endl;            
53             for(int j = 0; j < 6; j++){
54                 int s;
55                 cin >> s;
56                 SetBit(oriLights[i],j,s);
57             }
58         }
59     
60         for(int n=0; n<64; n++){
61             memcpy(lights,oriLights,sizeof(oriLights));
62             switchs = n;
63             // 每一个局部,第一行的开关方案就是该n,同时,在循环中switchs 也表示第i行的开关状态 
64             //第一行的开关选择,不是为了使得第一行灯为0,而是为了改变灯的状态,构造一个局部环境,产生一个局部条件。 
65             for(int i=0; i<5; i++){
66                 result[i] = switchs;//第i行开关方案 ,第0行的方案为n值,符合解题思路。result[0] = n;
67                 //首先要求出,第一行灯的状态,第一行的switch,改变本行的状态,它决定第二行的开关开法,使得第一行全灭。
68                 //下一次第二行开关拨发已经固定了,要求出第二行灯的状态,它决定第三行的开关开法,使得第二行全灭。             
69                 for(int j=0; j<6; j++){
70                     if(GetBit(switchs,j)){
71                         if(j>0)
72                             Flip(lights[i],j-1);
73                         if(j<5)
74                             Flip(lights[i],j+1);
75                         Flip(lights[i],j);
76                     }
77                 }
78                 //本行状态变化,决定下一行的switch 
79                 if(i<4)
80                     lights[i+1] ^= switchs; //下一行灯的状态发生改变
81                     
82                 switchs = lights[i]; //预先求出下一行的switchs 
83             } 
84             if(lights[4] == 0){
85                 OutputResult(t,result);
86                 break;
87             }
88         }
89     }    
90     return 0;
91     system("pause");
92 }

 

运行结果:

 

转载于:https://www.cnblogs.com/littleMa/p/8520042.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值