新手上路,可能有很多不足的地方,欢迎大家多多在留言区提出自己的观点以及更好的办法。
问题描述:俱乐部一共有32盏灯,设计一个灯光控制系统,共有4部分区域,其中台球部8盏,桌游区8盏,酒吧区8盏,休息区8盏,要求满足以下功能:
- 能独立控制每一盏灯
- 能一次性打开或关闭一个区域的全部灯光
- 能获取各个区域的灯开关情况
- 能一次性打开所有关闭的,关闭打开的灯
所用知识:
- c++基础语法
- 位运算<< ,>> , & , |
- 进制转换知识
注:所有数据的分析都是建立在二进制的数据形式下的
问题分析:32盏灯我们可以想到,一个 int 类型占4字节,一字节对应8bit,所以一个int类型可以转化成32bit。而int类型做位运算有很多不稳定的因素,比如正负数进行左右移运算时会有补1或0的情况等等,而使用unsigned(或unsigned int)同样是占用32bit,不管正负数左右移运算都是补0,稳定性好。
- 功能一分析:需要先右移到开/关灯的序号位置,然后加上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);
}
- 功能二分析:大家第一想到的是将一个区域用
~
来取反,再和原来的情况做& 或是 | 运算
吧,但是有一个问题就是怎么在不影响到其他的灯状态下来取反呢,我的办法很傻,就是把其他的数据通过位运算都变成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;
}
}
}
新手上路,可能有很多不足的地方,欢迎大家多多在留言区提出自己的观点以及更好的办法。