Quantas etapas são necessárias de n para 1 subtraindo o maior divisor?

50

Inspirado por esta pergunta em Matemática .


O problema

Let nSer um número natural ≥ 2. Pegue o maior divisor de n- que é diferente de nsi mesmo - e subtraia-o de n. Repita até você chegar 1.

A questão

Quantas etapas são necessárias para alcançar 1um determinado número n ≥ 2.

Exemplo Detalhado

Let n = 30.

O maior divisor de:

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

São necessários 6 passos para chegar 1.

Entrada

  • Entrada é um número inteiro n, onde n ≥ 2.
  • Seu programa deve oferecer suporte até o valor inteiro máximo do idioma.

Resultado

  • Basta imprimir o número de etapas, como 6.
  • Espaços em branco à esquerda / à direita ou novas linhas são bons.

Exemplos

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

Exigências

  • Você pode obter entrada de STDINargumentos de linha de comando, como parâmetros de função ou do equivalente mais próximo.
  • Você pode escrever um programa ou uma função. Se for uma função anônima, inclua um exemplo de como invocá-la.
  • Este é o pelo que a resposta mais curta em bytes vence.
  • As brechas padrão não são permitidas.

Esta série também pode ser encontrada no OEIS: A064097

Um quase-logaritmo definido indutivamente por a(1) = 0e a(p) = 1 + a(p-1)se pé primo e a(n*m) = a(n) + a(m)se m,n > 1.

insertusernamehere
fonte
esclarecer o requisito de entrada em idiomas com números inteiros de precisão arbitrários?
Sparr
@ Sparr eu diria, você deve pelo menos apoiar-se 2^32 - 1. O resto é com você e seu sistema. Espero que seja isso que você quis dizer com sua pergunta.
insertusernamehere
3
Eu gosto de como o título resume tudo
Luis Mendo

Respostas:

20

Geléia , 9 bytes

ÆṪÐĿÆFL€S

Experimente online! ou verifique todos os casos de teste .

fundo

A definição da sequência A064097 implica que

definição

Pela fórmula do produto de Euler

Fórmula do produto de Euler

onde φ denota a função totiente de Euler ep varia apenas sobre os números primos.

Combinando ambos, deduzimos a propriedade

primeira propriedade

onde ω denota o número de fatores primos distintos de n .

Aplicando o resultante fórmula k + 1 vezes, onde k é grande o suficiente de modo que φ k + 1 (n) = 1 , obtemos

segunda propriedade

A partir dessa propriedade, obtemos a fórmula

Fórmula

onde a última igualdade é válida porque ω (1) = 0 .

Como funciona

ÆṪÐĿÆ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.
Dennis
fonte
Agora essa é uma abordagem super inteligente!
Abr001am
15

05AB1E , 13 11 bytes

Código:

[DÒ¦P-¼D#]¾

Explicação:

[        ]   # 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.

Usa a codificação CP-1252 . Experimente online! .

Adnan
fonte
13
Remova o primeiro fator primo (o menor), a fim de obter o maior produto Que inteligente! :-)
Luis Mendo
Eu vejo, você é o desenvolvedor de linguagem
Sarge Borsch
@SargeBorsch Sim, isso é correto :)
Adnan
[¼Ñü-¤ÄD#]¾- Eu estava perto de raspar um byte com o par, oh bem ...
Magic Octopus Urn
-1 byte: [Ð#Ò¦P-¼]¾. Ðé melhor que DD.
Grimmy
11

Pitão, 11 bytes

fq1=-Q/QhPQ

Suíte de teste

Um loop direto de repetição até a verdade.

Explicação:

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
fonte
esse é um truque muito legal com o ffiltro.
Maltysen
3
Não entendo por que isso gera o número de vezes que a função foi executada. Esse é um recurso não documentado f?
CorsiKa
@corsiKa fsem um segundo argumento itera sobre todos os números inteiros positivos a partir de 1e retorna o primeiro valor que é verdadeiro na instrução interna. Esse valor não é usado neste programa, portanto, ele retorna o número de vezes que foi executado. Não documentado, apenas não ortodoxo :) Se ajudar, você pode pensar nisso como um forloop como:for(int i=1; some_condition_unrelated_to_i; i++) { change_stuff_that_affects_condition_but_not_i;}
FryAmTheEggman
@corsiKa Está documentado na referência de personagem no lado direito do intérprete online. Com apenas um argumento ( f <l:T> <none>), fé a primeira entrada em que A(_)acabou[1, 2, 3, 4...] .
Dennis
Ah, eu entendo agora. Ele usa essa entrada, mas nunca usa a entrada no cálculo . Isso explica o comentário de @Maltysen sobre "esse é um truque muito bom", porque você se importa apenas com a contagem de iterações que não usa essa contagem em nenhum lugar do filtro. Eu amo esses momentos ah-ha !:)
corsiKa
7

Python 2, 50 49 bytes

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

Isso não vai terminar o último caso de teste tão cedo ...

Como alternativa, aqui está um 48 bytes que retorna em Truevez de 1para n=2:

f=lambda n,k=1:n<3or n%(n-k)and f(n,k+1)or-~f(k)
Sp3000
fonte
6

Gelatina , 10 bytes

ÆfḊPạµÐĿi2

Experimente online! ou verifique a maioria dos casos de teste . Os últimos casos de teste são concluídos rapidamente localmente.

Como funciona

Æ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.
Dennis
fonte
5

Retina , 12

  • 14 bytes salvos graças a @ MartinBüttner
(1 +) (? = \ 1 + $)

Isso pressupõe a entrada dada em unário e a saída fornecida em decimal. Se isso não for aceitável, podemos fazer isso por mais 6 bytes:

Retina , 18

  • 8 bytes salvos graças a @ MartinBüttner
. +
$ *
(1 +) (? = \ 1 + $)

Experimente online - 1ª linha adicionada para executar todos os casos de teste de uma só vez.

Infelizmente, isso é unário para os cálculos, portanto, a entrada de 2016 155 não é prática.

  • O primeiro estágio (2 linhas) simplesmente converte a entrada decimal em unária como uma sequência de 1s
  • O segundo estágio (1 linha) calcula o maior fator de n usando grupos correspondentes de regex e olha para trás e efetivamente o subtrai de n. Esse regex corresponderá ao número de vezes necessário para reduzir o número o máximo possível. O número de correspondências de regex será o número de etapas e é gerado neste estágio.
Trauma Digital
fonte
Eu não acho que você precise do \b.
Martin Ender
Você pode economizar muito mais desse tipo e, tecnicamente, também não precisa do primeiro estágio .
Martin Ender
@ MartinBüttner Fantastic! Muito elegante - obrigado!
Digital Trauma
5

Pitão - 15 14 13 bytes

Invólucro especial 1está realmente me matando.

tl.u-N/Nh+PN2

Experimente online aqui .

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
fonte
11
Uma coisa que eu sempre esqueço .... força bruta é muitas vezes a abordagem golfiest
Leaky Nun
O que você quer dizer com revestimento especial 1?
Adnan
11
@ Adnan, a principal fatoração de 1é [], o que causa um erro quando pego o primeiro elemento. Eu tenho um caso especial para fazê-lo retornar 1novamente, para que o .uponto fixo termine. Eu encontrei uma maneira melhor do que .xtentar, exceto que é o que me salvou esses 2 bytes.
Maltysen
Ele só precisa aceitar números> = 2 (> 1).
Solomon Ucko
@SolomonUcko você está entendendo mal, o .uponto fixo acabará alcançando 1todas as informações, e nesse ponto terá que ser revestido de maneira especial.
Maltysen
5

JavaScript (ES6), * 44 38

Editar 6 bytes salvos graças a l4m2

(* 4 marcado ainda é 4)

Função recursiva

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

Menos golfe

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
}

Teste

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
fonte
Bom, mas eu acho que você deve gastar os dois bytes necessários para fazer f (1) == 0.
Neil
@ Neil pensando novamente: não. "Seja n um número natural ≥ 2 ..."
edc65 11/11/16
Eu preciso de novos óculos.
Neil
Por que não f=(n,d=n)=>n>1?n%--d?f(n,d):f(n-d)+1:0?
L4m2 13/04/19
@ l4m2 certo, por que não? Graças
edc65
4

Mathematica, 36 bytes

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

Uma função sem nome usa os mesmos bytes:

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

Essa é uma implementação muito direta da definição como uma função recursiva.

Martin Ender
fonte
4

Oitava, 59 58 55 bytes

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

Atualizado graças a Stewie Griffin, economizando 1 byte

Atualização adicional, economizando mais três bytes usando o resultado da fatoração na verificação durante a verificação.

Amostras de execuções:

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
fonte
é o último endnecessário na oitava?
Abr001am
Isto é. Percebi que não estava no matlab com as suas respostas, mas a Oitava espera isso (como aprendi ao experimentar as suas no Oitava).
Dcsohl
4

Haskell, 59 bytes

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

Uso:

Prelude> f 30
Prelude> 6

Pode ser um pouco ineficiente para grandes números por causa da geração da lista.

Alexandru Dinu
fonte
11
Compreensão da lista e <1, em vez de ==0salvar alguns bytes: f 1=0;f n=1+f(n-last[a|a<-[1..ndiv2],mod n a<1])
Angs
4

Julia, 56 50 45 39 bytes

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

Esta é uma função recursiva que aceita um número inteiro e retorna um número inteiro.

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

Experimente online! (inclui todos os casos de teste)

Economizou 6 bytes graças a Martin Büttner e 11 graças a Dennis!

Alex A.
fonte
3

PowerShell v2 +, 81 bytes

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

Mais brutal da força bruta.

Recebe entrada $a, entra em um forloop até que $aseja menor ou igual a 1. Cada loop passamos por outro forloop que faz a contagem regressiva $aaté encontrarmos um divisor ( !($a%$i). Na pior das hipóteses, vamos encontrar $i=1como um divisor. Quando o fazemos, incrementa nosso contador $j, subtrai nosso divisor $a-=$ie define $i=0para sair do loop interno. Eventualmente, chegaremos a uma condição em que o loop externo é falso (ou seja, $aatingiu 1), portanto, produza $je sai.

Cuidado : Isso levará muito tempo em números maiores, especialmente números primos. A entrada de 100.000.000 leva ~ 35 segundos no meu laptop Core i5. Editar - apenas testei com [int]::MaxValue(2 ^ 32-1) e levou ~ 27 minutos. Não é tão ruim, suponho.

AdmBorkBork
fonte
3

Matlab, 58 bytes

function p=l(a),p=0;if(a-1),p=1+l(a-a/min(factor(a)));end
Abr001am
fonte
3

Japt , 12 bytes (não concorrente)

@!(UµUk Å×}a

Teste online! Não concorrente porque usa vários recursos que foram adicionados após o lançamento do desafio.

Como funciona

@   !(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

Essa técnica foi inspirada na resposta 05AB1E . Uma versão anterior usada ²¤(pressione 2, corte os dois primeiros itens) no lugar Åporque é um byte mais curto que s1 (observe o espaço à direita); Eu só percebi depois do fato de que, como isso acrescenta um 2 ao final da matriz e fatias desde o início , ele de fato falha em qualquer número composto ímpar, embora funcione em todos os casos de teste.

ETHproductions
fonte
2

Python 3, 75, 70 , 67 bytes.

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]

Esta é uma solução recursiva bastante direta. Demora MUITO tempo para os casos de teste de número elevado.

Morgan Thrapp
fonte
2

> <>, 32 bytes

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

Espera o número de entrada,, nna pilha.

Este programa constrói a sequência completa na pilha. Como o único número que pode levar a isso 1é 2, a construção da sequência pára quando 2é atingido. Isso também faz com que o tamanho da pilha seja igual ao número de etapas, em vez do número de etapas +1.

Sok
fonte
2

Ruby, 43 bytes

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

Encontre o menor número ique xdivide x-ie recorra até chegarmos 1.

histocrata
fonte
2

Haskell, 67 bytes

Aqui está o código:

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&)

E aqui está uma razão pela qual Haskell é incrível:

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
  ]

Sim, no Haskell você pode definir -->como equivalente ==.

Michael Klein
fonte
2

Matlab, 107 bytes

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))
  • Não competitiva, essa não é a tradução iterativa da minha última submissão, apenas outro método algébrico direto, resume todos os logs binários de todos os fatores primários, meio ambíguo para ilustrar.
  • Vou jogar mais isso quando tiver tempo.
Abr001am
fonte
2

MATL, 17 16 bytes

`tttYfl)/-tq]vnq

Experimente Online

Explicação

        % 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
fonte
2

C99, 62 61 bytes

1 byte jogado fora por @Alchymist.

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

Chame como f (x, & y), onde x é a entrada e y é a saída.

mIllIbyte
fonte
Se você testar a% - b, poderá evitar eb no final. Uma economia de um byte inteiro.
Alchymist
2

Clojure, 116 104 bytes

(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 bytes, filtrando um intervalo para encontrar múltiplos e usando lastum para obter o melhor

Solução ingênua que basicamente resolve o problema, conforme descrito pelo OP. Infelizmente, encontrar o maior divisor sozinho ocupa metade dos bytes usados. Pelo menos eu deveria ter muito espaço para jogar golfe daqui.

Pré -olfo e teste:

(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
Carcinigenicado
fonte
11
@insertusernamehere Não, infelizmente, porque todos esses são identificadores válidos. Eu removi todo o espaço em branco possível. Se eu quiser jogar mais, vou precisar refazer o algoritmo.
precisa saber é o seguinte
2

Perl 6 , 35 bytes

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

Experimente online!

Como funciona

{                                 }   # 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
fonte
1

Pitão, 17 16 bytes

L?tbhy-b*F+1tPb0

Experimente online! (O y.vfinal é para chamada de função)


17 bytes originais:

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

Experimente online! (O y.vfinal é para chamada de função)

(Na verdade, eu respondi a essa pergunta com este programa Pyth.)

Freira Furada
fonte
Na verdade, eu não me incomodei em passar pelo seu programa, mas se você estiver usando a definição recursiva no OP, uprovavelmente será menor do que a recursão real.
Maltysen
1

Pyke, 11 bytes (não competitivo)

D3Phf-oRr;o

Isso usa um novo comportamento no qual, se houver uma exceção gerada após um goto, ele restaura o estado anterior ao goto (exceto definições de variáveis) e continua. Nesse caso, é equivalente ao seguinte código 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

Tudo isso é possível usando o Pyke sem uma construção de loop while - yay goto!

Experimente aqui!

Azul
fonte
1

JavaScript (ES6), 70 54 bytes

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

Implementação da fórmula recursiva fornecida, mas agora atualizada para usar a recursão para encontrar também o divisor.

Neil
fonte
1

Perl, 57 + 1 ( -psinalizador) = 58 bytes

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

Uso:

> 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 $\
}
Denis Ibaev
fonte
1

Clojure, 98 96 bytes

#(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))

usa for :whenpara encontrar o maior divisor, faz um loop até que nenhum valor maior que um seja encontrado.

NikoNyrh
fonte