我有一个等式:
x + y = x | y
如何解决这个等式?我需要找到方程所适用的第k个最小正整数y。也许有任何算法?我在哪里可以读到它? 因为我只是试图像这样解决它(在Pascal中):
uses crt;
var x,y,k,count:integer;
开始 readln(X,K); 计数:= 0;
for y:=1 to 10000 do
if((x+y) = (x or y)) then
begin
inc(count);
if(count = k) then
begin
WriteLn('y= ',y);
break;
end;
end;
但代码很慢!
提前致谢!
答案 0 :(得分:3)
可以通过在单个位值上对+
和|
进行简单观察来解决此等式:
0
,则两个操作都会生成0
,1
和0
或0
和1
时,两个操作都会产生1
,1
,则结果不同;另外,+
产生一个“进位”,它会改变相邻位。由于您正在寻找x + y
和x | y
组合的相等性,因此您需要检查的是两个数字中都没有设置为1的位。换句话说,任何一对x, y
使得x & y == 0
会使你的方程成立,而任何一对x & y != 0
都会使你的方程变为假。
为了查找给定k
等式所适用的y
最小x
,您可以尝试y
的所有值,递减k
每次找到x & y == 0
时。 k
达到零后,打印当前值y
。
答案 1 :(得分:2)
解决方案的总数是x和y值的可能组合总数的3/4。这是因为只要x + y内没有进位,你的方程就会得到满足。因此,对于每个位,相应的x和y位00,01和10的三个组合不产生进位,只有11个产生进位。
答案 2 :(得分:0)
我知道有一个公认的解决方案,但是有一种更快的方法来找到这个解决方案所持有的第k个最小整数,而不是像它推荐的那样强制解决方案。
由于您提到您的原始代码(使用此方法)太慢,我认为您想要一个具有 O(整数类型中的位)运行时复杂性的解决方案 。有了它,我可以在我的i7上大约1/10秒内为x = 1234567890
生成第一个500000解决方案(所有这些,而不仅仅是500000)(将输出重定向到/dev/null
,否则成为瓶颈),虽然这当然比用于有用的基准测试的时间更少,并且能够以大致相同的速度生成每个个体,而计算y
在这个例子中,蛮力方法中的第500000个解决方案将意味着检查超过5亿个数字。
关键的洞察力是,解决给定x + y = x | y
的等式x
的仅数字是那些具有{{1}中的位子集的数字设置。因此,这成为找到第k个最小的这样的子集的问题,并且可以通过二进制搜索来完成 - 这使得O(位)复杂度成为可能。
换句话说,知道在解决方案中可以使用哪些位使我们能够从最高位向下构建第k个解决方案,因为在第i个解决方案中设置了第n个最低位(可以使用的位)(在它尚未设置)生成(i + 2 n-1 )解决方案。这意味着我们可以遍历可用位,决定是否在我们当前拥有的解决方案中设置它将生成序数大于k的解决方案,并根据它设置或不设置。
代码是C ++,因为问题标记为C ++,我比Pascal更喜欢它。
~x
答案 3 :(得分:-1)
最简单的答案是否定:
unsigned y = ~x;
因为(x & ~x) == 0
。
要获得k-th
,您应该将k
的位映射到y
的1位。
这将只执行32(或使用x64时为64)步骤来完成。
unsigned find(unsigned y, unsigned k)
{
int i = 0, j = 0;
unsigned result = 0;
for (i = 0; i < sizeof(unsigned)*8; ++i)
{
if (y & (1 << i))
{
if (k & (1 << j))
result |= y & (1 << i);
++j;
if (k < (1 << j))
break; //we used all bits of k
}
if (y < (1 << i))
break; //we used all 1-bits of y
}
return result;
}
可视化:
y: 110010011
k: 11001
11 0 01 //we skip some position
r: 110000001
要获取拳头k
数字列表,您可以循环播放:
for (unsigned i = 1; i <= k; ++i)
std::cout << find(~x, i) << std::endl;