利用位运算控制开关灯问题

<C++笔记> 利用位运算控制开关灯问题

新手上路,可能有很多不足的地方,欢迎大家多多在留言区提出自己的观点以及更好的办法。

问题描述:俱乐部一共有32盏灯,设计一个灯光控制系统,共有4部分区域,其中台球部8盏,桌游区8盏,酒吧区8盏,休息区8盏,要求满足以下功能:

  1. 能独立控制每一盏灯
  2. 能一次性打开或关闭一个区域的全部灯光
  3. 能获取各个区域的灯开关情况
  4. 能一次性打开所有关闭的,关闭打开的灯

所用知识:

  1. c++基础语法
  2. 位运算<< ,>> , & , |
  3. 进制转换知识

注:所有数据的分析都是建立在二进制的数据形式下的

问题分析:32盏灯我们可以想到,一个 int 类型占4字节,一字节对应8bit,所以一个int类型可以转化成32bit。而int类型做位运算有很多不稳定的因素,比如正负数进行左右移运算时会有补1或0的情况等等,而使用unsigned(或unsigned int)同样是占用32bit,不管正负数左右移运算都是补0,稳定性好。

  1. 功能一分析:需要先右移到开/关灯的序号位置,然后加上1或-1(开灯+1,关灯-1),再左移回来,但是位移后右边的数都变成了0怎么解决呢,我的办法是在位移前面再定义一个unsigned变量,使其=开始没有位移时的数,然后对这个新变量进行左移到之前右移变成0的位置。再让这个新变量和之前的变量进行加法运算,这就还原了其他的灯状态。

部分代码如下`

//n是在主函数开头申明的
unsigned n=0;  //控制灯的主变量

while (true)
{
   
	unsigned x = 0;   //输入每盏灯的序号+返回号码
	unsigned m = n;   //辅助变量
	unsigned v = n;   //辅助变量
	std::cout << "灯的现有状态:" << bitset<32>(n) << char(10);
	
	cout << "请输入要开关的灯号码(1-32),输入0返回主页";
	cin >> x;
	
	//通过右移后的数和1做&运算,可以得到最后一位是0还是1
	unsigned i = (m >> (32 - x)) & 1;   //判断是0还是1(判断灯的开关状态)
	int b = pow(-1, i );   //是0的话表明是关的,就会+1 ,是1的话表明是开就会-1
	m = n;  //还原m的值
	
	if (x == 0)
	{
   
	    break;        
	}
	else
	    n = (((m >> (32 - x)) + int(b)) << (32 - x)) + ((v << x) >> x);
	    std::cout << "灯的改变后状态:" << bitset<32>(n) << char(10) << char(10);
}
  1. 功能二分析:大家第一想到的是将一个区域用~来取反,再和原来的情况做& 或是 | 运算吧,但是有一个问题就是怎么在不影响到其他的灯状态下来取反呢,我的办法很傻,就是把其他的数据通过位运算都变成0,然后对这个数据先~取反,再加上之前被暂时丢弃的数据

具体代码如下:

//n是在主函数开头申明的
unsigned  y;      //区域序号
int nf;           //判断开关灯
std::cout << "灯的现有状态:" << bitset<32>(n) << char(10);
cout << "请输入统一开关灯的区号:1.台球部  2.桌游区  3.酒吧区  4.休息区  (输入0返回主页)\n";
cin >> y;
if (y == 0)
   goto gogo;
cout << "1.开启此区域全部灯  2.关闭此区域全部灯,请输入序号:";
cin >> nf;
            
unsigned m = n;
unsigned u = n;
unsigned v = n;
unsigned c = n;
            
//我没有想到一个统一的算法,如果各位有好的方法的话还请指点一二
if (nf == 1)      //开灯时
{
   
                
   if (y >= 2 || y <= 3)
   {
   
       v = v >> (32 - 8 * (y - 1)) << (32 - 8 * (y - 1));
       c = c << (32 - 8 * (4 - y)) >> (32 - (4 - y) * 8);
       n = ((m >> (32 - 8 * y) << 24 >> (8 * (y - 1))) |
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
可以使用一个32位的整数来表示这32盏开关状态,其中第i位表示第i盏开关状态,0表示关闭,1表示打开。下面是实现上述功能的代码示例: ```python class LightControl: def __init__(self): self.lights = 0 # 初始状态所有都关闭 def turn_on(self, light_idx): # 打开指定编号的 self.lights |= (1 << light_idx) def turn_off(self, light_idx): # 关闭指定编号的 self.lights &= ~(1 << light_idx) def toggle(self, light_idx): # 切换指定编号的的状态 self.lights ^= (1 << light_idx) def turn_on_area(self, area): # 打开某个区域的所有 if area == '台球区': self.lights |= 0b11111111000000000000000000000000 elif area == '桌游区': self.lights |= 0b00000000111111110000000000000000 elif area == '酒吧区': self.lights |= 0b00000000000000001111111100000000 elif area == '休息区': self.lights |= 0b00000000000000000000000011111111 def turn_off_area(self, area): # 关闭某个区域的所有 if area == '台球区': self.lights &= 0b00000000111111111111111111111111 elif area == '桌游区': self.lights &= 0b11111111000000001111111111111111 elif area == '酒吧区': self.lights &= 0b11111111111111110000000011111111 elif area == '休息区': self.lights &= 0b11111111111111111111111100000000 def get_area_status(self, area): # 获取某个区域的开关情况 if area == '台球区': return (self.lights >> 24) & 0b11111111 elif area == '桌游区': return (self.lights >> 16) & 0b11111111 elif area == '酒吧区': return (self.lights >> 8) & 0b11111111 elif area == '休息区': return self.lights & 0b11111111 def turn_on_all(self): # 打开所有关闭的 self.lights = 0b11111111111111111111111111111111 def turn_off_all(self): # 关闭所有打开的 self.lights = 0b00000000000000000000000000000000 ``` 在上述代码中,我们使用了位运算来实现对单个控制、对整个区域的控制以及对所有控制。其中,左移操作 `<<` 和右移操作 `>>` 用于将某一位移动到最高或最低位,按位或操作 `|` 和按位与操作 `&` 用于设置或获取某一位的值,按位取反操作 `~` 和异或操作 `^` 用于切换某一位的值。具体可以参考 Python 的位运算符文档。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值