алгоритм для определения, состоит ли число из суммы, умноженной на два других числа - PullRequest
0 голосов
/ 14 мая 2018

допустим, что в качестве теста ему дано 2k+2+3p=n, как выяснить, является ли тест истинным для числа, допустимо для числа, когда k>=0, p>=0, n>=0:

example1: n = 24 следуетрезультат истина, так как k = 5 & p = 4 => 2 (5) + 2 + 3 (4) = 24

example2: n = 11 должен привести к истине, поскольку k = 0 & p = 3 => 2(0) + 2 + 3 (3) = 11

example3: n = 15 должно иметь значение true, поскольку 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 голосов
/ 15 мая 2018

Дейв уже дал конструктивный и эффективный ответ, но я хотел бы поделиться некоторыми математическими соображениями.

В течение некоторого времени я игнорирую часть + 2, так как она имеет меньшее значение, и сконцентрируюсь на общей форме этого вопроса: учитывая два положительных целых числа a и b, можно проверить, может ли быть число X представляется как k*a + m*b, где k и m - неотрицательные целые числа. Расширенный евклидов алгоритм по существу гарантирует, что:

  1. Если число X не делится на GCD(a,b), его нельзя представить как k*a + m*b с целыми числами k и m

  2. Если число X делится на GCD(a,b) и больше или равно a*b, его можно представить как k*a + m*b с неотрицательным целым числом 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, вы всегда можете получить оба коэффициента неотрицательными таким образом. (Примечание: это, очевидно, не самый эффективный способ найти подходящую пару этих коэффициентов, но, поскольку вы только спрашиваете, существуют ли такие коэффициенты, этого должно быть достаточно.)

  3. Таким образом, единственная серая область - это числа X, делимые на GCD(a,b), которые находятся в диапазоне (0, a*b). Я не знаю ни одного общего правила в этой области, но вы можете проверить это явно.

Таким образом, вы можете просто выполнить предварительные вычисления, описанные в # 3, а затем вы можете сразу же ответить на этот вопрос, просто сравнив + возможно проверяя предварительно вычисленный массив логических значений для диапазона (0, a*b).

Если ваш фактический вопрос касается формы k*a + m*b + c, где a, b и c являются фиксированными, он легко преобразуется в вопрос k*a + m*b, просто вычитая c из X.

Обновление (Большие значения a и b)

Если ваши a и b большие, и вы не можете заранее кэшировать диапазон (0, a*b), единственная идея, которую я имею, - это выполнить проверку значений в этом диапазоне по требованию с помощью достаточно эффективного алгоритма. Код выглядит так:

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;
    }
}

Идея этого кода основана на логике, описанной в шаге № 2 выше:

  1. Рассчитать коэффициенты GCD и Безу, используя расширенный евклидов алгоритм (если фиксированные a и b зафиксированы, это можно кэшировать, но даже если это не так быстро, в любом случае).
  2. Проверьте условия № 1 (определенно нет) и № 2 (определенно да) из приведенного выше
  3. Для значения в диапазоне (0, a*b) зафиксируйте некоторые коэффициенты, просто умножив коэффициенты Безу на X/gcd. F
  4. Найдите, какое из двух значений отрицательно, и найдите минимальный множитель, чтобы исправить это, обменяя один коэффициент на другой.
  5. Примените этот множитель к другому (изначально положительному) коэффициенту и проверьте, остается ли он положительным.

Этот алгоритм работает, потому что все возможные решения для X = k*a + m*b могут быть получены из некоторого базового решения (k0, m0), используя (k0 + n*b/gcd, m0 + n*a/gcd) для некоторого целого числа n. Таким образом, чтобы выяснить, существует ли решение с k >= 0 и m >= 0, все, что вам нужно, это найти решение с минимальным положительным значением k и проверить m для него.

Сложность этого алгоритма определяется логарифмическим алгоритмом Расширенного Евклида. Если это может быть кэшировано, все остальное просто постоянное время.

0 голосов
/ 15 мая 2018

Теорема : с помощью этой формулы можно представить число 2 и любое число> = 4.

Ответ : самый простойпроверка состоит в том, чтобы проверить, равно ли число 2 или больше или равно 4.

Доказательство : n=2k+2+3p, где k>=0, p>=0, n>=0 совпадает с n=2m+3p, где m>0, p>=0 и 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.Это правило выполняется для m больше или равно 3, то есть, начиная с n=5.Легко видеть, что для p=0 также возможны два дополнительных значения, n=2, n=4.

0 голосов
/ 14 мая 2018

По проверке, 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, чтобы добавить 2 к наименьшему действительному четному и нечетномучисла, чтобы получить все более четные и нечетные числа.

Все значения n> = 2 действительны, кроме 3.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...