当我解决Euler project problem #15时,我意识到它可以通过从开始到结束的路线组合方式来解决。生成的路径始终具有相同大小的向右或向下选择(或0和1),而正确的路径始终具有相同的0和1的数量。 因此,二进制字中具有相同数量0和1的数字的数量是 C(2,1)为1位长度 C(4,2)为2位“” C(6,3)为4位“” ...
现在我的问题出现了: 如果一个数字具有相同的0和1的数量,是否有一个函数可以解决? 我想它更像是一个逻辑函数,我不想迭代所有数字或使用正则表达式(这将比迭代更糟)。
**其他问题是关于这种“平衡”价值观之间的增长和空间吗?
答案 0 :(得分:5)
您正在寻找 popcount 函数,该函数计算给定数字中的设置位数。有些处理器内置了,有些则没有。
c=0; while (n &= (n-1)) c++;
完成工作,但会摧毁n
。
有关更好的算法,请参阅this link,或google“popcount”。
答案 1 :(得分:3)
作为Paul R答案的后续内容, 简化了中心二项式系数的公式,请参阅http://mathworld.wolfram.com/CentralBinomialCoefficient.html
p = n! /((n / 2)!)²= 2 n / 2 (n-1)!! /(n / 2)!
ķ!!是“双因子”,这意味着你在计算时跳过所有其他数字:k !! = k *(k-2)*(k-4)* ...(只要因子为正)。
对于你的计算,很多数字都会被取消(你可以在计算分子和分母时同时使用gcd)
答案 2 :(得分:1)
如果我理解正确,那么p = nCr
r = n/2
p = n! / ((n/2)! * (n/2)!)
。所以:
{{1}}
答案 3 :(得分:0)
可以通过想象你在路上选择路径来直接找到平衡值(即选择从n
开始2n
次。)
因此,这些值C(2n,n)
为2n! / (n! * n!)
。值的总数当然是2^2n
。使用斯特林的近似值,我们找到了
ln n! ~= n ln n - n + ln(2*pi*n)/2
ln 2n!/(n!*n!) = ln(2n!) - 2*ln(n!) ~= 2n*ln(2) - n + ln(4*pi*n)/2 - ln(2*pi*n)
这样好的值的分数C(2n,n)/2^(2n)
是
exp(2n*ln(2) - n + ln(4*pi*n)/2 - ln(2*pi*n) - 2n*ln(2)) =
exp(-n)/sqrt(pi*n)
因此,良好值的数量呈指数下降。
这就是为什么直接选择它们而不是测试它是明智的。
但如果你真的想测试,有各种比特计数方法here。 (Kernighan可能是最快的 - 但是他不是第一个注意到它的人,并且已经在这里发布了一个等效的算法!)
答案 4 :(得分:0)
您可以使用查找表将n-bt数字映射到其1-count。例如,如果您总是使用23位无符号整数,则16位和7位的查找表将允许您拆分数字,并从查找表中为16位和7位部分添加一位数。 (7位查找表可能只是16位表的一部分)。
答案 5 :(得分:0)
对于'i'的偶数值,2 ^ i和2 ^(i-1)之间的这些数字(等于1和0)的数量由以下公式给出:
(I-1)!/ [X! *(x-1)!]
其中x = i / 2。
我尝试在C中编写一个程序来生成它,但它溢出了。然后我用浮点运算做到了。直到我= 56它的好处。之后,准确度会下降。
但BigInt库应该能够完成这项任务而不会溢出。