刚入门c++,刚打完A+B的程序代码(可能算不上程序-_-!!!)就被学长调戏着问会不会能不能不用+号做A+B问题,当时一脸懵逼,以为有什么神奇的函数和算法,或者什么不入流的赖皮代码,今天偶然学了一下,也来螺旋升天秀一波!
思路流程
这是一道使用位运算的题目,很好,我们可以直接使用二进制来思考,因为c++是支持直接把数当二进制使用的。那么对于每一个位,都只有三种情况:
- 0+0=0;
- 1+0=1;
- 1+1=(1)0;
第一种和第二种是很简单的,因为没有进位,我们可以直接使用或运算:|,两者不同(1+0=1)为真,两者相同为假(0+0=0)。因为不存在1+1的进位情况。
第三种情况和第一种情况相比,是这题的难点:它们的结果都是0,但显然,它们对答案的影响完全不同!
所以,我在想有没有什么操作,可以记录下两个数都为1的情况。好在,有这样一个东西:&,符号与,意思是按二进制,两个位同真为真,其他为假。
那么,我们就可以得到一个新的二进制数,它的1表示进位,0表示没有进位。
例如,9(1001)+3(11):
进位了,之后该如何呢?
模仿加法的操作,我们相当于让原本加数的下一位+1,相当于,我们多了一个新的加数,“进位数”。所以我们需要两个东西:原本两个数相加的结果(没有进位),以及进位数。
第一个,刚好又有一个工具:异或,^,它的作用是安位,两位相同取0(0+0=0||1+1=0),否则取1(1+0=1)。
第二个,我们刚好有另一个工具,位运算:
a=< < k的意思是,把a的二进制全部左移k位,相当于乘以了2k2k;
我们用它,就可以很方便的解决这个问题了!进位数左移一位,现在把它和原来的结果相加就可以了!
最后一个问题:这个时候,相加仍可能进位,能进位怎么相加呢?我们必须找出不进位的结果,所以我们不断重复前两个动作,直至可以不进位相加为止。
代码如下:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 int main() 7 { 8 int a,b,c; 9 scanf("%d%d",&a,&b); 10 c=a&b; 11 while(c!=0) 12 { 13 a=a^b; 14 b=c<<1; 15 c=a&b; 16 } 17 printf("%d",a|b); 18 return 0; 19 }
顺便说一下,这个操作的时间复杂度是O(logn),所以除了花式秀操作,并没有什么卵用,但位运算的思想和这几个运算符,在后面会经常用到,所以请熟练它们。
这个可以很好的加强你对位运算的理解,所以这也不失为一道不错的题