用于确定数字是否由两个其他数的乘数之和组成的算法

时间:2018-05-14 17:26:11

标签: javascript algorithm math

让我们说它是2k+2+3p=n作为测试,如何找出测试是真的,一个数字对于k>=0, p>=0, n>=0时的数字是有效的:

  

example1:n = 24应该为真,因为k = 5& p = 4 => 2(5)+ 2 + 3(4)= 24

     

例2:n = 11应该为真,因为k = 0& p = 3 => 2(0)+ 2 + 3(3)= 11

     

例3:n = 15应该为真,因为k = 5& p = 1 => 2(5)+ 2 + 3(1)= 15

我想知道是否有一个数学解决方案。我像贝娄一样解决了它:

//let say 2k+2+3p=n
var accepted = false;
var betterNumber= n-2;
//assume p=0
var kReminder= (betterNumber)%2==0;
//assume k=0
var pReminder= (betterNumber)%3==0;

if (kReminder || pReminder){
    accepted=true;
}else{

    var biggerChunk= Math.Max(2,3); //max of 2k or 3p, here i try to find the bigger chunk of the 
    var smallerChunk= Math.Min(2,3);

    if ((betterNumber%bigger)%smallerChunk==0){
        accepted=true;
    }else
    {
        accepted=false;
    }    
}

仍然存在我没有看到的边缘情况。所以我想知道它是否有更好的解决方案。

更新

上面的测试只是一个例子。对于大数字或1000000k+37383993+37326328393p=747437446239902

这样的数字组合,解决方案应该足够有效

3 个答案:

答案 0 :(得分:2)

通过检查,2是最小有效偶数,5是最小有效奇数:

2 is valid (k=0, p=0)
5 is valid (k=0, p=1)

All even numbers >= 2 and all odd numbers >= 5 are valid.
Even numbers: k=n/2-1, p=0
odd numbers: k=(n-3)/2-1, p=1

我们在这里做的是递增k,将2s加到最小的有效偶数和奇数,以获得更大的偶数和奇数。

除了3之外,所有n> = 2的值都是有效的。

答案 1 :(得分:1)

戴夫已经提出了建设性和有效的答案,但我想在其背后分享一些数学知识。

有一段时间我会忽略+ 2部分,因为它不太重要,并专注于这个问题的一般形式:给出两个正整数ab检查是否数字X可以表示为k*a + m*b,其中km是非负整数。 Extended Euclidean algorithm基本上保证:

  1. 如果X无法将GCD(a,b)整除,则无法将k*a + m*b表示为整数km

  2. 如果数字X可被GCD(a,b)整除且大于或等于a*b,则可以将其表示为k*a + m*b,其中包含非负整数{{ 1}}和k。这是因为m可以用这种形式表示(我们称之为d = GCD(a,b))。如果d = k0*a + m0*bX = Y*d。如果这两个系数中的一个为负数,则可以根据X = (Y*k0)*a + (Y*m0)*b中的要求,将另一个系数换算为a*b。而且,因为X = (Y*k0 + b)*a + (Y*m0 - a)*b,你总是能够以这种方式使两个系数都是非负的。 (注意:这显然不是找到合适的那些系数对的最有效方法,但由于你只询问这些系数是否存在,它应该就足够了。)

  3. 因此,唯一的灰色区域是X >= a*b可被X整除的数字,位于GCD(a,b)范围之间。我不知道有关此区域的任何一般规则,但您可以明确检查。

  4. 所以你可以做#3中描述的预计算,然后你可以通过简单的比较立即回答这个问题+可能检查(0, a*b)范围的预先计算的布尔数组。

    如果您的实际问题是(0, a*b)表单k*a + m*b + cab已修复,则可以轻松将其转换为c问题从k*a + m*b中减去c

    更新Xa的大值)

    如果您的ba很大,那么您无法事先缓存b范围,我唯一的想法是按需检查该范围内的值通过合理有效的算法。代码如下:

    (0, a*b)

    此代码背后的理念基于上述步骤#2中描述的逻辑:

    1. 使用扩展欧几里德算法计算GCD和Bézout系数(如果function egcd(a0, b0) { let a = a0; let b = b0; let ca = [1, 0]; let cb = [0, 1]; while ((a !== b) && (b !== 0)) { let r = a % b; let q = (a - r) / b; let cr = [ca[0] - q * cb[0], ca[1] - q * cb[1]]; a = b; ca = cb; b = r; cb = cr; } return { gcd: a, coef: ca }; } function check(a, b, x) { let eg = egcd(a, b); let gcd = eg.gcd; let c0 = eg.coef; if (x % gcd !== 0) return false; if (x >= a * b) return true; let c1a = c0[0] * x / gcd; let c1b = c0[1] * x / gcd; if (c1a < 0) { let fixMul = -Math.floor(c1a / (b / gcd)); let c1bFixed = c1b - fixMul * (a / gcd); return c1bFixed >= 0; } else { //c1b < 0 let fixMul = -Math.floor(c1b / (a / gcd)); let c1aFixed = c1a - fixMul * (b / gcd); return c1aFixed >= 0; } } a是固定的,这可以缓存,但即使不是这样也是相当快的。)
    2. 从以上
    3. 检查条件#1(绝对没有)和#2(肯定是)
    4. 对于b范围内的值,只需将Bézout系数乘以(0, a*b)即可修复一些系数。 ˚F
    5. 找出两者中的哪一个为负数,并通过将一个系数换成另一个系数来找到修正它的最小乘数。
    6. 将此乘数应用于另一个(最初为正)系数,并检查它是否仍然为正。
    7. 此算法有效,因为X/gcd的所有可能解决方案都可以从某个基本解X = k*a + m*b获取,使用(k0, m0)作为某个整数(k0 + n*b/gcd, m0 + n*a/gcd)。因此,要了解是否存在同时包含nk >= 0的解决方案,您只需要找到最小正数m >= 0的解决方案并检查k。< / p>

      该算法的复杂性由对数的扩展欧几里德算法支配。如果它可以被缓存,那么其他一切都只是不变的时间。

答案 2 :(得分:0)

定理:可以使用此公式表示数字2 任意数字&gt; = 4。

答案:最简单的测试是检查数字是等于2还是更大或等于4。

证明n=2k+2+3p其中k>=0, p>=0, n>=0n=2m+3pm>0, p>=0的{​​{1}}相同。使用m=k+1可以代表任何甚至号码,例如使用p=0可以代表m=10。此偶数左侧的奇数数字可以使用n=20来表示,例如m'=m-2, p=1。右侧的奇数号码可以用19=2*8+3表示,例如m'=m-1, p=1。此规则适用于21=2*9+3大于或等于3,即从m开始。很容易看出,对于n=5,还有两个额外的值,p=0n=2