算法1.枚举法解决熄灯问题

这篇博客介绍了一种利用枚举法解决熄灯问题的算法,具体是从北大郭炜老师的课程中得到的启示。题目描述了一个按钮矩阵,按下按钮会影响其周围灯的状态,目标是找出按下哪些按钮能熄灭所有灯。博主通过分析得出只需枚举第一行的26种情况即可,并提供了解题思路和简化操作的方法。
摘要由CSDN通过智能技术生成

枚举法解熄灯问题

北大郭炜老师:程序与算法(二)

题目描述

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

请你写一个程序,确定需要按下哪些按钮,恰好使得所有的灯都熄灭。根据上面的规则,我们知道
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

解题流程

看到这道题后,想起了刚学c语言时八皇后的问题,然后就对这道题产生了兴趣。
解题规则郭炜老师在一开始就说了
1.每个按钮按一次即可
2.顺序对结果无影响
3.对第1行中每盏点亮的灯,按下第2行对应的按钮,就可以熄灭第1行的全部灯。如此重复下去,可以熄灭第1、2、3、4行的全部灯。同样,按下第1、2、3、4、5列的按钮,可以熄灭前5列的灯。

解题的关键就在于第三点
这道题如果我每种情况都枚举出来的话,一共是232种,显然是不合理的,而第三种规则告诉了我们这里只用枚举第一行26种情况即可。
我们用两列灯来举个简单的例子
假如为
0 0 1 1 0 1
0 1 1 0 1 1
首先枚举第一种情况,即按下第一行第一列的灯,然后就变成了:
1 1 1 1 0 1
1 0 1 0 1 1
这种情况下我要想最后第一行第一列的灯为0的话,那么我一定要按下第二行第一列的灯,即第二行的灯是否要被按下是受第一行所控制的,同理,第三行也受第二行的控制,这样依次推下去我们会发现,后面几行灯是否被按下,全部受第一行控制,所以在枚举时只需要枚举出第一行的所有情况即可。

在进行枚举的时候,为了减少时间和空间开销,我们可以将二维数组转化为一维数组
因为二维数据每个位置的值只能是0或者1
假如第一行为 0 0 1 1 0 1,那么我们新建的一维数组的第一位的值就为13,每次更改的时候采用位运算就行了,这里不做过多描述

首先写出三个函数方便待会使用

//输入的时候用到
int getbit (char c,int i)
{
   
	return (c>>i)&1;
}
//将c的第i位设置为v
char setbit (char c,int i,int v)
{
   
	if(v)
	return c|(1<<i);
	else 
	return 	c &( ~(1<<i));
}
//翻转c的第i位
char 
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值