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

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

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

问题描述:俱乐部一共有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))) | (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v + c;
   }
   if (y == 1)
   {
       v = v << 8 >> 8;
       n = ((m >> (32 - 8 * y) << 24 >> (8 * (y - 1))) | (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v;
                }
    if (y == 4)
    {
       v = v >> 8 << 8;

       n = ((m >> (32 - 8 * y) << 24 >> (8 * (y - 1))) | (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v;
    }
std::cout << "灯的改变后状态:" << bitset<32>(n) << char(10) << char(10);
}

if (nf == 2)   //关灯时
{
     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))) & (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v + c;
     }
     if (y == 1 )
     {
         v = v << 8 >> 8;
         n = ((m >> (32 - 8 * y) << 24 >> (8 * (y - 1))) & (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v ;
     }
     if (y == 4)
     {
         v = v >> 8 << 8;

         n = ((m >> (32 - 8 * y) << 24 >> (8 * (y - 1))) & (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v;
     }

std::cout << "灯的改变后状态:" << bitset<32>(n) << char(10) << char(10);
}

其他两个问题就简单许多了,功能3我已经在上面的代码中实现了,主要运用了bitset的语句:std::cout << "灯的状态:" << bitset<32>(n) <
功能4就是运用~来取反然后用&将原来的值和取反后的值进行运算就行了。

全部代码如下:

#include 
#include 
using namespace std;
int main()
{  
    unsigned n=0;
    unsigned xx;

gogo:
    system("cls");
    cout << "灯的现有状态:" << bitset<32>(n) << char(10);
    cout << "1.改变单个灯状态\n2.改变一组灯状态\n3.一次性打开关闭的灯,关闭打开的灯\n(输入0退出系统)请输入序号:";
    cin >> xx;

    system("cls");
    while (xx != 0)
    {
        //改变单个灯
        if (xx == 1)
        {
            system("cls");
            while (true)
            {
                unsigned x = 0;   //每盏灯的序号+返回号码
                unsigned m = n;
                unsigned v = n;
                std::cout << "灯的现有状态:" << bitset<32>(n) << char(10);
                

                cout << "请输入要开关的灯号码(1-32),输入0返回主页";
                cin >> x;
                
                unsigned i = (m >> (32 - x) ) & 1;
                int b = pow(-1, i );
                m = n;

                if (x == 0)
                {
                    goto gogo;
                }
                else
                     n = (((m >> (32 - x)) + int(b)) << (32 - x)) + ((v << x) >> x);
                    std::cout << "灯的改变后状态:" << bitset<32>(n) << char(10) << char(10);
            }
        }

        //改变一个区域灯
        if (xx == 2)
        {
            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))) | (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v + c;
                }
                if (y == 1)
                {
                    v = v << 8 >> 8;
                    n = ((m >> (32 - 8 * y) << 24 >> (8 * (y - 1))) | (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v;
                }
                if (y == 4)
                {
                    v = v >> 8 << 8;

                    n = ((m >> (32 - 8 * y) << 24 >> (8 * (y - 1))) | (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v;
                }
                std::cout << "灯的改变后状态:" << bitset<32>(n) << char(10) << char(10);
            }
            if (nf == 2)
            {
                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))) & (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v + c;
                }
                if (y == 1 )
                {
                    v = v << 8 >> 8;
                    n = ((m >> (32 - 8 * y) << 24 >> (8 * (y - 1))) & (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v ;
                }
                if (y == 4)
                {
                    v = v >> 8 << 8;

                    n = ((m >> (32 - 8 * y) << 24 >> (8 * (y - 1))) & (~u >> (32 - 8 * y) << 24 >> (8 * (y - 1)))) + v;
                }

                std::cout << "灯的改变后状态:" << bitset<32>(n) << char(10) << char(10);
            }

        }
    
       //一次性打开关闭的灯,关闭打开的灯
        if (xx == 3)
        {
            
            cout << "灯的现有状态:" << bitset<32>(n) << char(10);
            int x;
            cout << "1.一次性打开关闭的灯,关闭打开的灯  0.返回主页";
            
            cin >> x;
            if (x == 1)
            {
                n = ~n;
                cout << "灯的改变后状态:" << bitset<32>(n) << char(10) << char(10);
            }
            else
                goto gogo;
            
        }
    }
}

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

你可能感兴趣的:(c++,c++)