Сколько шагов требуется от n до 1, вычитая наибольший делитель?

50

Вдохновленный этим вопросом закончил в математике .


Проблема

Позвольте nбыть натуральным числом ≥ 2. Возьмите самый большой делитель n- который отличается от nсамого себя - и вычтите его n. Повторяйте, пока не получите 1.

Вопрос

Сколько шагов нужно, чтобы достичь 1определенного числа n ≥ 2.

Подробный пример

Пусть n = 30.

Величайший делитель:

1.   30 is 15  -->  30 - 15 = 15
2.   15 is  5  -->  15 -  5 = 10
3.   10 is  5  -->  10 -  5 =  5
4.    5 is  1  -->   5 -  1 =  4
5.    4 is  2  -->   4 -  2 =  2
6.    2 is  1  -->   2 -  1 =  1

Требуется 6 шагов, чтобы добраться 1.

вход

  • Ввод является целым числом n, где n ≥ 2.
  • Ваша программа должна поддерживать ввод до максимального целочисленного значения языка.

Выход

  • Просто выведите количество шагов, например 6.
  • Лидирующие / завершающие пробелы или переводы строк в порядке.

Примеры

f(5)        --> 3
f(30)       --> 6
f(31)       --> 7
f(32)       --> 5
f(100)      --> 8
f(200)      --> 9
f(2016^155) --> 2015

Требования

  • Вы можете получить входные данные из STDINаргументов командной строки как параметры функции или из ближайшего аналога.
  • Вы можете написать программу или функцию. Если это анонимная функция, пожалуйста, включите пример того, как ее вызвать.
  • Это поэтому выигрывает самый короткий ответ в байтах.
  • Стандартные лазейки запрещены.

Эту серию можно также найти на OEIS: A064097

Квазилогарифм, индуктивно определяемый как a(1) = 0и a(p) = 1 + a(p-1)если pпростое и a(n*m) = a(n) + a(m)если m,n > 1.

insertusernamehere
источник
уточнить требования к вводу в языках с родными целыми числами произвольной точности?
Спарр
@ Sparr Я бы сказал, вы должны по крайней мере поддерживать до 2^32 - 1. Остальное зависит от вас и вашей системы. Надеюсь, это то, что вы имели в виду под своим вопросом.
insertusername здесь
3
Мне нравится, как заголовок подводит итоги
Луис Мендо

Ответы:

20

Желе , 9 байт

ÆṪÐĿÆFL€S

Попробуйте онлайн! или проверьте все контрольные примеры .

Фон

Определение последовательности A064097 подразумевает, что

определение

По формуле Эйлера

Формула продукта Эйлера

где φ обозначает функцию Эйлера, а p изменяется только по простым числам.

Объединяя оба, мы выводим свойство

первое свойство

где ω обозначает число различных простых множителей n .

Применяя полученную формулу k + 1 раз, где k достаточно велико, так что φ k + 1 (n) = 1 , получаем

второе свойство

Из этого свойства получаем формулу

формула

где выполняется последнее равенство, потому что ω (1) = 0 .

Как это устроено

ÆṪÐĿÆFL€S  Main link. Argument: n

  ÐĿ       Repeatedly apply the link to the left until the results are no longer
           unique, and return the list of unique results.
ÆṪ           Apply Euler's totient function.
           Since φ(1) = 1, This computes φ-towers until 1 is reached.
    ÆF     Break each resulting integer into [prime, exponent] pairs.
      L€   Compute the length of each list.
           This counts the number of distinct prime factors.
        S  Add the results.
Деннис
источник
Теперь это очень умный подход!
Abr001am
15

05AB1E , 13 11 байт

Код:

[DÒ¦P-¼D#]¾

Объяснение:

[        ]   # An infinite loop and...
       D#        break out of the loop when the value is equal to 1.
 D           # Duplicate top of the stack (or in the beginning: duplicate input).
  Ò          # Get the prime factors, in the form [2, 3, 5]
   ¦         # Remove the first prime factor (the smallest one), in order to get 
               the largest product.
    P        # Take the product, [3, 5] -> 15, [] -> 1.
     -       # Substract from the current value.
      ¼      # Add one to the counting variable.
          ¾  # Push the counting variable and implicitly print that value.

Использует кодировку CP-1252 . Попробуйте онлайн! ,

Аднан
источник
13
Удалите первый простой множитель (самый маленький), для того , чтобы получить самый большой продукт Как умный! :-)
Луис Мендо
Я вижу, вы разработчик языка
Sarge Borsch
@SargeBorsch Да, это правильно :)
Аднан
[¼Ñü-¤ÄD#]¾- Я был близок к тому, чтобы сбрить байт попарно, ну ладно ...
Волшебный осьминог Урна
-1 байт: [Ð#Ò¦P-¼]¾. Ðлучше чем DD.
Grimmy
11

Pyth, 11 байт

fq1=-Q/QhPQ

Тестирование

Простая петля повторения до истины.

Объяснение:

fq1=-Q/QhPQ
               Implicit: Q = eval(input())
f              Apply the following function until it is truthy,
               incrementing T each time starting at 1:
         PQ    Take the prime factorization of Q
        h      Take its first element, the smallest factor of Q
      /Q       Divide Q by that, giving Q's largest factor
    -Q         Subtract the result from Q
   =           Assign Q to that value
 q1            Check if Q is now 1.
isaacg
источник
это действительно хороший трюк с fИлтером.
Maltysen
3
Я не понимаю, почему это выводит число раз, когда функция выполнялась. Это недокументированная особенность f?
CorsiKa
@corsiKa fбез второго аргумента перебирает все положительные целые числа, начиная с, 1и возвращает первое значение, которое дает true для внутреннего оператора. Это значение оказывается неиспользованным в этой программе, поэтому оно возвращает количество раз, которое оно запустило. Не документировано, просто неортодоксально :) Если это поможет, вы можете думать об этом как о forцикле вроде:for(int i=1; some_condition_unrelated_to_i; i++) { change_stuff_that_affects_condition_but_not_i;}
FryAmTheEggman
@corsiKa Это задокументировано в справочнике по символам в правой части онлайн-переводчика. Имея только один аргумент ( f <l:T> <none>), fэто Первый вход, где A(_)истина окончена[1, 2, 3, 4...] .
Деннис
Ах, я понимаю это сейчас. Он использует этот вход, но никогда не использует вход в расчете . Это объясняет комментарий @Maltysen «это действительно хороший трюк», потому что вы заботитесь только о количестве итераций, не используя его в любом месте вашего фильтра. Я люблю эти моменты ах-ха !
:)
7

Python 2, 50 49 байтов

f=lambda n,k=1:2/n or n%(n-k)and f(n,k+1)or-~f(k)

Этот последний тест не закончится в ближайшее время ...

В качестве альтернативы вот 48 байтов, которые возвращаются Trueвместо 1for n=2:

f=lambda n,k=1:n<3or n%(n-k)and f(n,k+1)or-~f(k)
Sp3000
источник
6

Желе , 10 байт

ÆfḊPạµÐĿi2

Попробуйте онлайн! или проверьте большинство тестовых случаев . Последние контрольные примеры быстро заканчиваются локально.

Как это устроено

ÆfḊPạµÐĿi2  Main link. Argument: n (integer)

Æf          Factorize n, yielding a list of primes, [] for 1, or [0] for 0.
  Ḋ         Dequeue; remove the first (smallest) element.
   P        Take the product.
            This yields the largest proper divisor if n > 1, 1 if n < 2.
    ạ       Yield the abs. value of the difference of the divisor (or 1) and n.
     µ      Convert the chain to the left into a link.
      ÐĿ    Repeatedly execute the link until the results are no longer unique.
            Collect all intermediate results in a list.
            For each starting value of n, the last results are 2 -> 1 -> 0 (-> 1).
        i2  Compute the 1-based index of 2.
Деннис
источник
5

Сетчатка , 12

  • 14 байтов сохранено благодаря @ MartinBüttner
(1 +) (? = \ 1 + $)

Это предполагает ввод данных в унарном формате и вывод данных в десятичном формате. Если это неприемлемо, мы можем сделать это еще на 6 байтов:

Сетчатка , 18

  • 8 байтов сэкономлено благодаря @ MartinBüttner
. +
$ *
(1 +) (? = \ 1 + $)

Попробуйте онлайн - добавлена ​​1-я строка для запуска всех тестов за один раз.

К сожалению, это использует унарный для расчетов, поэтому ввод 2016 года 155 не практично.

  • Первый этап (2 строки) просто преобразует десятичный ввод в унарный в виде строки 1s
  • Второй этап (1 строка) вычисляет наибольший множитель n с помощью сопоставления с регулярными выражениями, просматривает и эффективно вычитает его из n. Это регулярное выражение будет соответствовать столько раз, сколько необходимо, чтобы уменьшить число, насколько это возможно. Число совпадений с регулярным выражением будет числом шагов и выводится на этом этапе.
Цифровая травма
источник
Я не думаю, что вам нужно \b.
Мартин Эндер
Вы можете сэкономить гораздо больше, хотя и технически вам не нужен и первый этап .
Мартин Эндер
@ MartinBüttner Фантастика! Очень элегантно - спасибо!
Цифровая травма
5

Pyth - 15 14 13 байт

Специальный корпус 1действительно убивает меня.

tl.u-N/Nh+PN2

Попробуйте это онлайн здесь .

tl                One minus the length of
 .u               Cumulative fixed point operator implicitly on input
  -N              N -
   /N             N /
    h             Smallest prime factor
     +PN2         Prime factorization of lambda var, with two added to work with 1
Maltysen
источник
1
Одна вещь, которую я всегда забываю ... грубая сила - часто самый лучший подход
Leaky Nun
Что вы имеете в виду под специальным корпусом 1?
Аднан
1
@ Adnan основная факторизация 1is [], которая вызывает ошибку, когда я беру первый элемент. Мне нужно в особом случае, чтобы он 1снова вернулся, чтобы .uфиксированная точка закончилась. Я нашел лучший способ, чем .xпопытаться, за исключением того, что спасло мне эти 2 байта.
Maltysen
Нужно только принять числа> = 2 (> 1).
Соломон Уцко
@SolomonUcko, вы неправильно поняли, .uфиксированная точка в конечном итоге достигнет 1всех входных данных, после чего она должна быть в специальном регистре.
Maltysen
5

JavaScript (ES6), * 44 38

Редактировать 6 байтов сохранено благодаря @ l4m2

(* 4 пораженных - все еще 4)

Рекурсивная функция

f=(n,d=n)=>n>1?n%--d?f(n,d):f(n-d)+1:0

Меньше гольфа

f=(n, d=n-1)=>{
  if (n>1)
    if(n % d != 0)
      return f(n, d-1) // same number, try a smaller divisor
    else
      return f(n-d)+1  // reduce number, increment step, repeat
  else
    return 0
}

Контрольная работа

f=(n,d=n)=>n>1?n%--d?f(n,d):f(n-d)+1:0

console.log=x=>O.textContent+=x+'\n';

[5,30,31,32,100,200].forEach(x=>console.log(x+' -> '+f(x)))
<pre id=O></pre>

edc65
источник
Хорошо, но я думаю, что вы должны потратить два байта, необходимые для получения f (1) == 0.
Нил
@ Нил снова подумал: нет. «Пусть n натуральное число ≥ 2 ...»
edc65
Мне нужны новые очки.
Нейл
Почему нет f=(n,d=n)=>n>1?n%--d?f(n,d):f(n-d)+1:0?
14 м2,
@ l4m2 правильно, а почему бы и нет? Спасибо
edc65
4

Mathematica, 36 байт

f@1=0;f@n_:=f[n-Divisors[n][[-2]]]+1

Безымянная функция занимает те же байты:

If[#<2,0,#0[#-Divisors[#][[-2]]]+1]&

Это очень простая реализация определения как рекурсивной функции.

Мартин Эндер
источник
4

Октава, 59 58 55 байт

function r=f(x)r=0;while(x-=x/factor(x)(1));r++;end;end

Обновлен благодаря Stewie Griffin, сэкономив 1 байт

Дальнейшее обновление, сохраняя еще три байта, используя результат факторизации в while-проверке.

Образцы прогонов:

octave:41> f(5)
ans =  3
octave:42> f(30)
ans =  6
octave:43> f(31)
ans =  7
octave:44> f(32)
ans =  5
octave:45> f(100)
ans =  8
octave:46> f(200)
ans =  9
dcsohl
источник
последнее endнеобходимо в октаве?
Abr001am
Это. Я заметил, что это не было в matlab из твоих ответов, но Octave ожидает этого (как я узнал, попробовав твой в Octave).
августа
4

Haskell, 59 байт

f 1=0;f n=1+(f$n-(last$filter(\x->n`mod`x==0)[1..n`div`2]))

Использование:

Prelude> f 30
Prelude> 6

Это может быть немного неэффективно для больших чисел из-за генерации списка.

Александру Дину
источник
1
Перечислите понимание и <1вместо того, чтобы ==0сохранить несколько байтов: f 1=0;f n=1+f(n-last[a|a<-[1..ndiv2],mod n a<1])
Angs
4

Юлия, 56 50 45 39 байт

f(n)=n>1&&f(n-n÷first(factor(n))[1])+1

Это рекурсивная функция, которая принимает целое число и возвращает целое число.

Ungolfed:

function f(n)
    if n < 2
        # No decrementing necessary
        return 0
    else
        # As Dennis showed in his Jelly answer, we don't need to
        # divide by the smallest prime factor; any prime factor
        # will do. Since `factor` returns a `Dict` which isn't
        # sorted, `first` doesn't always get the smallest, and
        # that's okay.
        return f(n - n ÷ first(factor(n))[1]) + 1
    end
end

Попробуйте онлайн! (включает все тестовые случаи)

Сэкономили 6 байтов благодаря Мартину Бюттнеру и 11 благодаря Деннису!

Алекс А.
источник
3

PowerShell v2 +, 81 байт

param($a)for(;$a-gt1){for($i=$a-1;$i-gt0;$i--){if(!($a%$i)){$j++;$a-=$i;$i=0}}}$j

Самый грубый из грубой силы.

Принимает ввод $a, входит в forцикл до тех пор, пока не $aстанет меньше или равен 1. Каждый цикл мы проходим через другой forцикл, который отсчитывается от, $aпока мы не найдем делитель ( !($a%$i). В худшем случае мы найдем $i=1в качестве делителя. Когда мы это сделаем, увеличьте наш счетчик $j, вычтите наш делитель $a-=$iи установите $i=0выход из внутреннего цикла. В конце концов, мы достигнем условия, когда внешний цикл ложен (то $aесть достиг 1), поэтому выводим $jи выходим.

Внимание : это займет много времени на больших числах, особенно простых. Ввод 100 000 000 занимает ~ 35 секунд на моем ноутбуке Core i5. Редактировать - только что протестировано с [int]::MaxValue(2 ^ 32-1), и это заняло ~ 27 минут. Полагаю, не так уж и плохо.

AdmBorkBork
источник
3

Matlab, 58 байт

function p=l(a),p=0;if(a-1),p=1+l(a-a/min(factor(a)));end
Abr001am
источник
3

Japt , 12 байт (не конкурирует)

@!(UµUk Å×}a

Проверьте это онлайн! Не конкурирует, потому что использует множество функций, которые были добавлены после публикации заявки.

Как это устроено

@   !(Uµ Uk Å  ×   }a
XYZ{!(U-=Uk s1 r*1 }a
                       // Implicit: U = input integer
XYZ{               }a  // Return the smallest non-negative integer X which returns
                       // a truthy value when run through this function:
         Uk            //   Take the prime factorization of U.
            s1         //   Slice off the first item.
                       //   Now we have all but the smallest prime factor of U.
               r*1     //   Reduce the result by multiplication, starting at 1.
                       //   This takes the product of the array, which is the
                       //   largest divisor of U.
      U-=              //   Subtract the result from U.
    !(                 //   Return !U (which is basically U == 0).
                       //   Since we started at 0, U == 1 after 1 less iteration than
                       //   the desired result. U == 0 works because the smallest
                       //   divisor of 1 is 1, so the next term after 1 is 0.
                       // Implicit: output result of last expression

Эта техника была вдохновлена ответом 05AB1E . Использовалась предыдущая версия ²¤(нажмите 2, отрежьте первые два элемента) вместо, Åпотому что она на один байт короче s1 (обратите внимание на конечный пробел); Я понял только после того факта, что, поскольку это добавляет 2 к концу массива и срезы с самого начала , он фактически завершается ошибкой на любом нечетном составном числе, хотя он работает на всех заданных тестовых примерах.

ETHproductions
источник
2

Python 3, 75, 70 , 67 байт.

g=lambda x,y=0:y*(x<2)or[g(x-z,y+1)for z in range(1,x)if x%z<1][-1]

Это довольно прямое рекурсивное решение. Это займет ОЧЕНЬ много времени для тестовых случаев с большим количеством.

Морган Трепп
источник
2

> <>, 32 байта

<\?=2:-$@:$/:
1-$:@@:@%?!\
;/ln

Ожидается ввод числа nв стеке.

Эта программа строит полную последовательность в стеке. В качестве единственного числа , которое может привести к 1ИБ 2, построение последовательности останавливается , когда 2достигается. Это также приводит к тому, что размер стека равен количеству шагов, а не количеству шагов +1.

Sok
источник
2

Рубин, 43 байта

f=->x{x<2?0:1+f[(1..x).find{|i|x%(x-i)<1}]}

Найдите наименьшее число, iтакое, которое xделит x-iи повторяйте, пока мы не достигнем 1.

histocrat
источник
2

Haskell, 67 байт

Вот код:

a&b|b<2=0|a==b=1+2&(b-1)|mod b a<1=1+2&(b-div b a)|1<2=(a+1)&b
(2&)

И вот одна из причин, почему Haskell потрясающий:

f = (2&)

(-->) :: Eq a => a -> a -> Bool
(-->) = (==)

h=[f(5)        --> 3
  ,f(30)       --> 6
  ,f(31)       --> 7
  ,f(32)       --> 5
  ,f(100)      --> 8
  ,f(200)      --> 9
  ,f(2016^155) --> 2015
  ]

Да, в Haskell вы можете определить, -->чтобы быть эквивалентным ==.

Майкл Кляйн
источник
2

Matlab, 107 байт

a=input('');b=factor(a-isprime(a));c=log2(a);while(max(b)>1),b=max(factor(max(b)-1));c=c+1;end,disp(fix(c))
  • Не конкурирующий, это не итеративный перевод моей последней заявки, а просто еще один прямой алгебраический метод, он суммирует все двоичные записи всех простых факторов, как бы двусмысленно проиллюстрировать.
  • Я буду играть в гольф больше, когда у меня будет время.
Abr001am
источник
2

MATL, 17 16 байт

`tttYfl)/-tq]vnq

Попробуйте онлайн

объяснение

        % Implicitly grab input
`       % Do while loop
    ttt % Make three copies of top stack element
    Yf  % Compute all prime factors
    l)  % Grab the smallest one
    /   % Divide by this to get the biggest divisor
    -   % Subtract the biggest divisor
    t   % Duplicate the result
    q   % Subtract one (causes loop to terminate when the value is 1). This
        % is functionally equivalent to doing 1> (since the input will always be positive) 
        % with fewer bytes
]       % End do...while loop
v       % Vertically concatenate stack contents (consumes entire stack)
n       % Determine length of the result
q       % Subtract 1 from the length
        % Implicitly display result
Suever
источник
2

C99, 62 61 байт

@Alchymist удаляет 1 байт

f(a,c,b)long*c,a,b;{for(*c=0,b=a;a^1;a%--b||(++*c,b=a-=b));}  

Вызовите как f (x, & y), где x - это вход, а y - это выход.

mIllIbyte
источник
Если вы проверяете a% - b, тогда вы можете избежать b-- в конце. Сохранение всего одного байта.
Алхимик
2

Clojure, 116 104 байта

(fn[n](loop[m n t 1](let[s(- m(last(filter #(=(rem m %)0)(range 1 m))))](if(< s 2)t(recur s (inc t))))))

-12 байт, фильтруя диапазон, чтобы найти кратные, затем используя lastодин, чтобы получить самый большой

Наивное решение, которое в основном просто решает проблему, как описано в ОП. К сожалению, только нахождение наибольшего делителя занимает половину используемых байтов. По крайней мере, у меня должно быть много места для игры в гольф отсюда.

Прегольфед и тест:

(defn great-divider [n]
  ; Filter a range to find multiples, then take the last one to get the largest
  (last
     (filter #(= (rem n %) 0)
             (range 1 n))))

(defn sub-great-divide [n]
  (loop [m n
         step 1]
    (let [g-d (great-divider m) ; Find greatest divisor of m
          diff (- m g-d)] ; Find the difference
      (println m " is " g-d " --> " m " - " g-d " = " diff)
      (if (< diff 2)
        step
        (recur diff (inc step))))))

(sub-great-divide 30)

30  is  15  -->  30  -  15  =  15
15  is  5  -->  15  -  5  =  10
10  is  5  -->  10  -  5  =  5
5  is  1  -->  5  -  1  =  4
4  is  2  -->  4  -  2  =  2
2  is  1  -->  2  -  1  =  1
6
Carcigenicate
источник
1
@insertusernamehere Нет, к сожалению, потому что это все действительные идентификаторы. Я удалил все возможные пробелы. Если я захочу поиграть в гольф дальше, мне нужно переделать алгоритм.
Carcigenicate
2

Perl 6 , 35 байт

{+({$_ -first $_%%*,[R,] ^$_}...1)}

Попробуйте онлайн!

Как это устроено

{                                 }   # A bare block lambda.
                    [R,] ^$_          # Construct range from arg minus 1, down to 0.
        first $_%%*,                  # Get first element that is a divisor of the arg.
    $_ -                              # Subtract it from the arg.
   {                        }...1     # Do this iteratively, until 1 is reached.
 +(                              )    # Return the number of values generated this way.
SMLS
источник
1

Pyth, 17 16 байт

L?tbhy-b*F+1tPb0

Попробуйте онлайн! y.vконце для вызова функции)


Оригинал 17 байтов:

L?tb+1y-b*F+1tPb0

Попробуйте онлайн! y.vконце для вызова функции)

(Я действительно ответил на этот вопрос с помощью этой программы Pyth.)

Дрянная Монахиня
источник
Я на самом деле не удосужился пройтись по вашей программе, но если вы используете рекурсивное определение в OP, u вероятно, оно короче реальной рекурсии.
Maltysen
1

Пайк, 11 байт (неконкурентный)

D3Phf-oRr;o

При этом используется новое поведение, при котором, если после goto возникает исключение, оно восстанавливает состояние до перехода к goto (кроме определений переменных) и продолжает работу. В этом случае это эквивалентно следующему коду Python:

# Implicit input and variable setup
inp = input()
o = 0
# End implicit
try:
    while 1:
        inp -= factors(inp)[0] # If factors is called on the value 1, it returns an empty
                               # list which when the first element tries to be accessed
                               # raises an exception
        o += 1 # Using `o` returns the current value of `o` and increments it
except:
    print o # This in effect gets the number of times the loop went

Это все возможно, используя Pyke без создания цикла while - ура!

Попробуй это здесь!

синий
источник
1

JavaScript (ES6), 70 54 байта

f=(n,i=2)=>n<i?0:n%i?f(n,i+1):n>i?f(i)+f(n/i):1+f(n-1)

Реализация предоставленной рекурсивной формулы, но теперь она обновлена ​​для использования рекурсии, чтобы также найти делитель.

Нил
источник
1

Perl, 57 + 1 ( -pфлаг) = 58 байт

$n=$_;$n-=$n/(grep!($n%$_),2..$n/2,$n)[0],$\++while$n>1}{

Использование:

> echo 31 | perl -pe '$n=$_;$n-=$n/(grep!($n%$_),2..$n/2,$n)[0],$\++while$n>1}{'

Ungolfed:

while (<>) {
# code above added by -p
    # $_ has input value
    # $\ has undef (or 0)
    my $n = $_;
    while ($n > 1) {
        my $d = 1;
        for (2 .. ($n / 2)) {
            if ($n % $_ == 0) {
                $d = $n / $_;
                last;
            }
        }
        $n -= $d;
        $\++;
    }
} {
# code below added by -p
    print;  # prints $_ (undef here) and $\
}
Денис Ибаев
источник
1

Clojure, 98 96 байт

#(loop[n % i -1](if n(recur(first(for[j(range(dec n)0 -1):when(=(mod n j)0)](- n j)))(inc i))i))

используется for :whenдля поиска наибольшего делителя, циклически повторяется до тех пор, пока не будет найдено значение, большее, чем единица.

NikoNyrh
источник