让我们说它是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
答案 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
部分,因为它不太重要,并专注于这个问题的一般形式:给出两个正整数a
和b
检查是否数字X
可以表示为k*a + m*b
,其中k
和m
是非负整数。 Extended Euclidean algorithm基本上保证:
如果X
无法将GCD(a,b)
整除,则无法将k*a + m*b
表示为整数k
和m
如果数字X
可被GCD(a,b)
整除且大于或等于a*b
,则可以将其表示为k*a + m*b
,其中包含非负整数{{ 1}}和k
。这是因为m
可以用这种形式表示(我们称之为d = GCD(a,b)
)。如果d = k0*a + m0*b
则X = Y*d
。如果这两个系数中的一个为负数,则可以根据X = (Y*k0)*a + (Y*m0)*b
中的要求,将另一个系数换算为a*b
。而且,因为X = (Y*k0 + b)*a + (Y*m0 - a)*b
,你总是能够以这种方式使两个系数都是非负的。 (注意:这显然不是找到合适的那些系数对的最有效方法,但由于你只询问这些系数是否存在,它应该就足够了。)
因此,唯一的灰色区域是X >= a*b
可被X
整除的数字,位于GCD(a,b)
范围之间。我不知道有关此区域的任何一般规则,但您可以明确检查。
所以你可以做#3中描述的预计算,然后你可以通过简单的比较立即回答这个问题+可能检查(0, a*b)
范围的预先计算的布尔数组。
如果您的实际问题是(0, a*b)
表单k*a + m*b + c
,a
和b
已修复,则可以轻松将其转换为c
问题从k*a + m*b
中减去c
。
更新(X
和a
的大值)
如果您的b
和a
很大,那么您无法事先缓存b
范围,我唯一的想法是按需检查该范围内的值通过合理有效的算法。代码如下:
(0, a*b)
此代码背后的理念基于上述步骤#2中描述的逻辑:
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
是固定的,这可以缓存,但即使不是这样也是相当快的。)b
范围内的值,只需将Bézout系数乘以(0, a*b)
即可修复一些系数。 ˚F此算法有效,因为X/gcd
的所有可能解决方案都可以从某个基本解X = k*a + m*b
获取,使用(k0, m0)
作为某个整数(k0 + n*b/gcd, m0 + n*a/gcd)
。因此,要了解是否存在同时包含n
和k >= 0
的解决方案,您只需要找到最小正数m >= 0
的解决方案并检查k
。< / p>
该算法的复杂性由对数的扩展欧几里德算法支配。如果它可以被缓存,那么其他一切都只是不变的时间。
答案 2 :(得分:0)
定理:可以使用此公式表示数字2 和任意数字&gt; = 4。
答案:最简单的测试是检查数字是等于2还是更大或等于4。
证明:n=2k+2+3p
其中k>=0, p>=0, n>=0
与n=2m+3p
和m>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=0
,n=2
。