Quanti passi ci vuole da n a 1 sottraendo il massimo divisore?


50

Ispirato da questa domanda alla Matematica .


Il problema

Lascia che nsia un numero naturale ≥ 2. Prendi il più grande divisore di n- che è diverso da nse stesso - e sottralo n. Ripeti fino ad ottenere 1.

La domanda

Quanti passaggi sono necessari per raggiungere 1un determinato numero n ≥ 2.

Esempio dettagliato

Let n = 30.

Il più grande divisore di:

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

Ci vogliono 6 passi per raggiungere 1.

Ingresso

  • L'input è un numero intero n, dove n ≥ 2.
  • Il tuo programma dovrebbe supportare input fino al valore intero massimo della lingua.

Produzione

  • Emetti semplicemente il numero di passaggi, come 6.
  • Gli spazi bianchi o le righe iniziali / finali vanno bene.

Esempi

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

Requisiti

  • È possibile ottenere input da STDINargomenti della riga di comando, come parametri di funzione o dall'equivalente più vicino.
  • È possibile scrivere un programma o una funzione. Se si tratta di una funzione anonima, si prega di includere un esempio di come invocarlo.
  • Questo è quindi la risposta più breve in byte vince.
  • Le scappatoie standard non sono ammesse.

Questa serie è disponibile anche su OEIS: A064097

Un quasi-logaritmo definito induttivamente da a(1) = 0e a(p) = 1 + a(p-1)se pè primo e a(n*m) = a(n) + a(m)se m,n > 1.


chiarire il requisito di input in lingue con interi di precisione arbitrari nativi?
Sparr,

@Sparr Direi che dovresti almeno supportare fino a 2^32 - 1. Il resto dipende da te e dal tuo sistema. Spero, questo è ciò che intendevi con la tua domanda.
insertusernamehere

3
Mi piace come il titolo riassuma tutto
Luis Mendo,

Risposte:


20

Gelatina , 9 byte

ÆṪÐĿÆFL€S

Provalo online! o verifica tutti i casi di test .

sfondo

La definizione della sequenza A064097 implica che

definizione

Dalla formula del prodotto di Eulero

Formula del prodotto di Eulero

dove φ indica la funzione di totaggio di Eulero e p varia solo sui numeri primi.

Combinando entrambi, deduciamo la proprietà

prima proprietà

dove ω indica il numero di fattori primi distinti di n .

Applicando la formula risultante k + 1 volte, dove k è abbastanza grande in modo che φ k + 1 (n) = 1 , otteniamo

seconda proprietà

Da questa proprietà, otteniamo la formula

formula

dove l'ultima uguaglianza vale perché ω (1) = 0 .

Come funziona

ÆṪÐĿÆ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.

Questo è un approccio super intelligente!
Abr001,

15

05AB1E , 13 11 byte

Codice:

[DÒ¦P-¼D#]¾

Spiegazione:

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

Utilizza la codifica CP-1252 . Provalo online! .


13
Rimuovi il primo fattore primo (il più piccolo), per ottenere il prodotto più grande Che intelligenza! :-)
Luis Mendo,

Vedo, sei lo sviluppatore del linguaggio
Sarge Borsch,

@SargeBorsch Sì, è vero :)
Adnan,

[¼Ñü-¤ÄD#]¾- Ero vicino alla rasatura di un byte con coppia, oh beh ...
Magic Octopus Urn

-1 byte: [Ð#Ò¦P-¼]¾. Ðè meglio di DD.
Grimmy,

11

Pyth, 11 byte

fq1=-Q/QhPQ

Suite di test

Un semplice ciclo di ripetizione fino a vero.

Spiegazione:

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.

è davvero un bel trucco con filter.
Maltysen,

3
Non capisco perché questo emetta il numero di volte in cui la funzione è stata eseguita. È questa una caratteristica non documentata di f?
corsiKa

@corsiKa fsenza un secondo argomento scorre su tutti gli interi positivi a partire da 1e restituisce il primo valore che fornisce true sull'istruzione interna. Questo valore sembra non essere utilizzato in questo programma, quindi restituisce il numero di volte in cui è stato eseguito. Non privo di documenti, solo poco ortodosso :) Se aiuta, puoi pensare a questo come ad un forciclo come:for(int i=1; some_condition_unrelated_to_i; i++) { change_stuff_that_affects_condition_but_not_i;}
FryAmTheEggman

@corsiKa È documentato nel riferimento al personaggio sul lato destro dell'interprete online. Con solo un argomento ( f <l:T> <none>), fè il primo input in cui la A(_)verità è finita[1, 2, 3, 4...] .
Dennis,

Ah lo capisco adesso. Usa quell'input ma non usa mai l'input nel calcolo . Questo spiega il commento di @Maltysen di "è davvero un bel trucco" perché ti preoccupi solo del conteggio delle iterazioni che non usa quel conteggio ovunque nel tuo filtro. Adoro quei momenti ah-ah !
:)

7

Python 2, 50 49 byte

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

Questo non finirà presto l'ultimo caso di test ...

In alternativa, ecco un 48 byte che restituisce Trueinvece di 1per n=2:

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

6

Gelatina , 10 byte

ÆfḊPạµÐĿi2

Provalo online! o verifica la maggior parte dei casi di test . Gli ultimi casi di test terminano rapidamente localmente.

Come funziona

Æ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

Retina , 12

  • 14 byte salvati grazie a @ MartinBüttner
(1 +) (? = \ 1 + $)

Ciò presuppone l' input fornito in unario e l'output in decimale. Se questo non è accettabile, possiamo farlo per altri 6 byte:

Retina , 18 anni

  • 8 byte salvati grazie a @ MartinBüttner
. +
$ *
(1 +) (? = \ 1 + $)

Provalo online - Prima riga aggiunta per eseguire tutti i test in una volta sola.

Purtroppo questo utilizza unario per i calcoli, quindi l'input del 2016 155 non è pratico.

  • Il primo stadio (2 righe) converte semplicemente l'input decimale in unario come una stringa di 1s
  • Il secondo stadio (1 riga) calcola il più grande fattore di n usando gruppi di corrispondenza regex e lookbehinds e lo sottrae efficacemente da n. Questa regex corrisponderà quante volte è necessario per ridurre il numero il più possibile. Il numero di corrispondenze regex sarà il numero di passaggi e viene emesso da questo stadio.

Non penso che tu abbia bisogno di \b.
Martin Ender,


@ MartinBüttner Fantastico! Molto elegante - grazie!
Trauma digitale

5

Pyth - 15 14 13 byte

Un involucro speciale 1mi sta davvero uccidendo.

tl.u-N/Nh+PN2

Provalo online qui .

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

1
Una cosa che dimentico sempre .... la forza bruta è spesso l'approccio più golfoso
Leaky Nun,

Cosa intendi con involucro speciale 1?
Adnan,

1
@Adnan la scomposizione in fattori primi di 1is [], che causa un errore quando prendo il primo elemento. Devo un caso speciale per farlo tornare di 1nuovo in modo che il .upunto fisso termini. Ho trovato un modo migliore di .xprovare, tranne che è ciò che mi ha salvato quei 2 byte.
Maltysen,

Deve solo accettare numeri> = 2 (> 1).
Solomon Ucko,

@SolomonUcko sei frainteso, il .upunto fisso alla fine raggiungerà 1per tutti gli input, a quel punto dovrà essere inserito in un caso speciale.
Maltysen,

5

JavaScript (ES6), * 44 38

Modifica 6 byte salvati grazie a @ l4m2

(* 4 colpito è ancora 4)

Funzione ricorsiva

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

Meno golf

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
}

Test

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>


Bene, ma penso che dovresti spendere i due byte necessari per rendere f (1) == 0.
Neil,

@Neil ripensandoci: no. "Sia n un numero naturale ≥ 2 ..."
edc65,

Ho bisogno di nuovi occhiali.
Neil,

Perché no f=(n,d=n)=>n>1?n%--d?f(n,d):f(n-d)+1:0?
l4m2

@ l4m2 giusto, perché no? Grazie
edc65,

4

Mathematica, 36 byte

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

Una funzione senza nome accetta gli stessi byte:

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

Questa è un'implementazione molto semplice della definizione come funzione ricorsiva.


4

Ottava, 59 58 55 byte

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

Aggiornato grazie a Stewie Griffin, risparmiando 1 byte

Ulteriore aggiornamento, salvando altri tre byte utilizzando il risultato della fattorizzazione in while-check.

Esecuzioni campione:

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

è l'ultimo endnecessario in ottava?
Abr001,

È. Ho notato che non era in matlab dalle tue risposte, ma Octave se lo aspetta (come ho imparato provando le tue in Octave).
dcsohl,

4

Haskell, 59 byte

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

Potrebbe essere un po 'inefficiente per i grandi numeri a causa della generazione dell'elenco.


1
Comprendi l'elenco e <1invece di ==0salvare qualche byte: f 1=0;f n=1+f(n-last[a|a<-[1..ndiv2],mod n a<1])
Ang

4

Julia, 56 50 45 39 byte

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

Questa è una funzione ricorsiva che accetta un numero intero e restituisce un numero intero.

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

Provalo online! (include tutti i casi di test)

6 byte salvati grazie a Martin Büttner e 11 grazie a Dennis!


3

PowerShell v2 +, 81 byte

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

Più brutale della forza bruta.

Accetta input $a, entra in un forloop fino a quando $aè minore o uguale a 1. Ogni ciclo attraversiamo un altro forciclo che conta alla rovescia $afino a quando non troviamo un divisore ( !($a%$i). Nel peggiore dei casi, troveremo $i=1come divisore. Quando lo facciamo, incrementiamo il nostro contatore $j, sottraggiamo il nostro divisore $a-=$ie impostiamo $i=0per uscire dal circuito interno. Alla fine, raggiungeremo una condizione in cui il loop esterno è falso (ovvero, $aha raggiunto 1), quindi output $je exit.

Attenzione : questo richiederà molto tempo su numeri più grandi, specialmente numeri primi. L'immissione di 100.000.000 richiede ~ 35 secondi sul mio laptop Core i5. Modifica : appena testato con [int]::MaxValue(2 ^ 32-1) e ci sono voluti ~ 27 minuti. Non troppo male, suppongo.


3

Matlab, 58 byte

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

3

Japt , 12 byte (non concorrenti)

@!(UµUk Å×}a

Provalo online! Non competitiva perché utilizza una serie di funzionalità aggiunte dopo la pubblicazione della sfida.

Come funziona

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

Questa tecnica è stata ispirata dalla risposta 05AB1E . È stata utilizzata una versione precedente ²¤(premere un 2, tagliare i primi due elementi) al posto di Åperché è un byte più corto di s1 (spazio finale della nota); Mi sono reso conto solo dopo che, poiché questo aggiunge un 2 alla fine dell'array e delle sezioni dall'inizio , in realtà non riesce su alcun numero composito dispari, sebbene funzioni su tutti i casi di test forniti.


2

Python 3, 75, 70 , 67 byte.

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]

Questa è una soluzione ricorsiva piuttosto semplice. Ci vuole molto tempo per i casi di test con un numero elevato.


2

> <>, 32 byte

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

Si aspetta il numero di input,, nnello stack.

Questo programma crea la sequenza completa nello stack. Poiché l'unico numero che può portare a 1è 2, la costruzione della sequenza si interrompe quando 2viene raggiunta. Questo fa sì che la dimensione della pila sia uguale al numero di passaggi, anziché al numero di passaggi +1.


2

Rubino, 43 byte

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

Trova il numero più piccolo itale da xdividere x-ie ricorrere fino al raggiungimento 1.


2

Haskell, 67 byte

Ecco il codice:

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

Ed ecco uno dei motivi per cui Haskell è fantastico:

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
  ]

Sì, in Haskell puoi definire -->l'equivalente di ==.


2

Matlab, 107 byte

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))
  • Non competitiva, questa non è la traduzione iterativa della mia ultima sottomissione, solo un altro metodo algerinico diretto, riassume tutti i registri binari di tutti i fattori primi, un po 'ambigui da illustrare.
  • Giocherò a golf di più quando avrò tempo.

2

MATL, 17 16 byte

`tttYfl)/-tq]vnq

Provalo online

Spiegazione

        % 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

2

C99, 62 61 byte

1 byte eliminato da @Alchymist.

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

Chiama come f (x, & y), dove x è l'input e y è l'output.


Se provi a% - b, puoi evitare b-- alla fine. Un intero risparmio di byte.
Alchymist,


2

Clojure, 116 104 byte

(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 byte filtrando un intervallo per trovare multipli, quindi utilizzandone lastuno per ottenere il massimo

Soluzione ingenua che sostanzialmente risolve il problema come descritto dall'OP. Sfortunatamente, trovare il massimo divisore da solo occupa come metà dei byte utilizzati. Almeno dovrei avere un sacco di spazio per giocare a golf da qui.

Pregolfato e prova:

(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

1
@inserireusernamehere No, sfortunatamente, perché sono tutti identificatori validi. Ho rimosso tutto lo spazio bianco possibile. Se voglio continuare a giocare a golf, dovrò rielaborare l'algoritmo.
Carcigenicato il

2

Perl 6 , 35 byte

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

Provalo online!

Come funziona

{                                 }   # 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.

1

Pyth, 17 16 byte

L?tbhy-b*F+1tPb0

Provalo online! (Alla y.vfine è per la chiamata di funzione)


17 byte originali:

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

Provalo online! (Alla y.vfine è per la chiamata di funzione)

(In realtà ho risposto a questa domanda con questo programma Pyth.)


In realtà non mi sono preoccupato di passare attraverso il tuo programma, ma se stai usando la definizione ricorsiva nell'OP, uè probabilmente più breve della ricorsione effettiva.
Maltysen,

1

Pyke, 11 byte (non competitivo)

D3Phf-oRr;o

Questo utilizza un nuovo comportamento in cui se si verifica un'eccezione dopo un goto, ripristina lo stato precedente al goto (tranne le definizioni delle variabili) e continua. In questo caso è equivalente al seguente codice 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

Tutto ciò è possibile usando Pyke senza una costruzione ad anello while - yay vai!

Provalo qui!


1

JavaScript (ES6), 70 54 byte

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

Implementazione della formula ricorsiva fornita, ma ora aggiornata per usare la ricorsione per trovare anche il divisore.


1

Perl, 57 + 1 ( -pflag) = 58 byte

$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 $\
}

1

Clojure, 98 96 byte

#(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 :whenper trovare il divisore più grande, loops fino a quando non viene trovato tale valore maggiore di uno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.