Алгоритм вычисления k долей формы 1/r суммирования до 1

Учитывая k, нам нужно написать 1 как сумму фракций k формы 1/r.

Например,

  • Для k=2, 1 можно однозначно записать как 1/2 + 1/2.
  • Для k=3, 1 может быть записано как 1/3 + 1/3 + 1/3 или 1/2 + 1/4 + 1/4 или 1/6 + 1/3 + 1/2

Теперь нам нужно рассмотреть весь такой набор фракций k, которые суммируются до 1 и возвращают наивысший знаменатель среди всех таких множеств; например, пример 2, наш алгоритм должен возвращать 6.

Я столкнулся с этой проблемой в конкурсе кодирования и не смог найти алгоритм для этого. Несколько позже поиск Google показал, что такие фракции называются Egyption Fractions, но, вероятно, они представляют собой различные фракции, суммирующие до определенного значения (не как 1/2 + 1/2). Кроме того, я не мог найти алгоритм для вычисления Liberation Fractions (если они вообще полезны для этой проблемы), когда их число ограничено k.

Ответ 1

Если все, что вы хотите сделать, это найти самый большой знаменатель, нет никаких причин для поиска всех возможностей. Вы можете сделать это очень просто:

public long largestDenominator(int k){
    long denominator = 1;
    for(int i=1;i<k;i++){
        denominator *= denominator + 1;
    } 
    return denominator;
}

Для рекурсивных типов:

public long largestDenominator(int k){
    if(k == 1)
        return 1;
    long last = largestDenominator(k-1);
    return last * (last + 1); // or (last * last) + last)
}

Почему это так просто?

Чтобы создать набор, вам нужно вставить самую большую дробь, которая будет хранить ее под 1 на каждом шаге (кроме последнего). Под "большой долей" я имею в виду значение, означая наименьший знаменатель.

Для простого случая k=3 это означает, что вы начинаете с 1/2. Вы не можете подобрать другую половину, так что вы идете с 1/3. Затем 1/6 остается, предоставляя вам три слова.

В следующем случае k=4 вы берете 1/6 с конца, так как он не подпадает под один, и нам нужно место для другого термина. Замените его 1/7, так как это самое большое значение, которое подходит. Остальная часть 1/42.

Повторите при необходимости.


Например:

  • 2: [2,2]
  • 3: [2,3,6]
  • 4: [2,3,7,42]
  • 5: [2,3,7,43,1806]
  • 6: [2,3,7,43,1807,3263442]

Как вы можете видеть, он быстро становится очень большим. Достаточно быстро, чтобы вы переполнили long, если k>7. Если вам нужно это сделать, вам нужно будет найти соответствующий контейнер (например, BigInteger в Java/С#).

Он отлично отображает эту последовательность:

a(n) = a(n-1)^2 + a(n-1), a(0)=1.

Вы также можете увидеть отношение к последовательность Сильвестра:

a(n+1) = a(n)^2 - a(n) + 1, a(0) = 2

Wikipedia имеет очень приятную статью, объясняющую взаимосвязь между ними, как отметил Питер в комментариях.

Ответ 2

Я никогда не слышал о египетских фракциях, но вот несколько мыслей:

Идея

Вы можете думать о них геометрически:

  • Начните с квадрата единицы (1x1)
  • Нарисуйте вертикальные или горизонтальные линии, разделяющие квадрат на равные части.
  • Повторяйте произвольное рисование строк внутри любого из подборок равномерно.
  • Остановитесь в любое время.

Представленные прямоугольники образуют набор дробей вида 1/n, которые добавляют к 1.

Вы можете подсчитать их, и они могут равняться вашему "k".

В зависимости от того, сколько равных разделов вы разделили прямоугольник, в нем будет указано, есть ли у вас 1/2 или 1/3 или что-то еще. 1/6 составляет 1/2 1/3 или 1/3 1/2. (т.е. вы нырнули на 2, а затем один из подборок на 3 ИЛИ наоборот).

Идея 2

Вы начинаете с 1 окна. Это доля 1/1 с k = 1.

Если вы разделите n на n, вы добавите n к числу полей (k или суммированных сумм) и вычтите 1.

Когда вы разделите один из этих полей, снова вычтите 1 и добавьте n, количество делений. Обратите внимание, что n-1 - это количество строк, которые вы нарисовали, чтобы разделить их.

Подробнее

Вы начнете поиск ответа с помощью k. Очевидно, k * 1/k = 1, поэтому у вас есть одно решение.

Как насчет k-1?

Там есть решение: (k-2) * 1/(k-1) + 2 * (1/((k-1) * 2))

Как я понял? Я сделал k-1 равных частей (с k-2 вертикальными линиями), а затем разделил последний пополам по горизонтали.

Каждое решение будет состоять из:

  • принимая предварительное решение
  • используя j меньше строк и некоторую стадию, и разделив один из ящиков или под-ящиков на j + 1 равные секции.

Я не знаю, могут ли быть сформированы все решения, повторяя это правило, начиная с k * 1/k

Я знаю, что вы можете получить эффективные дубликаты таким образом. Например: k * 1/k с j = 1 = > (k-2) * 1/(k-1) + 2 * (1/((k-1) * 2)) [сверху], но k * 1/k с j = (k-2) = > 2 * (1/((k-1) * 2)) + (k-2) * 1/(k-1) [который просто меняет порядок части]

Интересный

k = 7 может быть представлено 1/2 + 1/4 + 1/8 +... + 1/(2 ^ 6) + 1/(2 ^ 6), а общий случай равен 1/2 +... + 1/(2 ^ (k-1)) + 1/(2 ^ (k-1)).

Аналогично для любого нечетного k его можно представить в виде 1/3 +... + 3 * [1/(3 ^ ((k-1)/2)].

Я подозреваю, что существуют похожие шаблоны для всех целых чисел до k.