Percorsi più brevi in ​​un grafico divisore


15

introduzione

In questa sfida, avremo a che fare con un certo infinito grafico non orientato, che io chiamo il grafico ad alto divisore . I suoi nodi sono numeri interi a partire da 2. C'è un bordo tra due nodi a <b se a divide b e a 2 ≥ b . Il sottografo formato dall'intervallo da 2 a 18 è simile al seguente:

16-8 12 18
  \|/ |/|
   4  6 9 10 15 14
   |  |/   |/   |
   2  3    5    7  11 13 17

Si può dimostrare che il grafico del divisore alto infinito è collegato, quindi possiamo chiedere il percorso più breve tra due nodi.

Ingresso e uscita

I suoi ingressi sono due interi a e b . Si può presumere che 2 ≤ a ≤ b <1000 . L'output è la lunghezza del percorso più breve tra una e b nell'infinito grafico alta divisore. Ciò significa che il numero di spigoli nel percorso.

Potresti trovare utile il seguente fatto: esiste sempre un percorso ottimale da a a b che prima aumenta e poi diminuisce e visita solo nodi che sono rigorosamente inferiori a 2b 2 . In particolare, poiché b <1000 è necessario considerare solo nodi inferiori a 2 000 000.

Esempi

Considera gli input 3e 32. Un possibile percorso tra i nodi 3 e 32 è

3 -- 6 -- 12 -- 96 -- 32

Questo percorso ha quattro bordi e si scopre che non ci sono percorsi più corti, quindi l'output corretto è 4.

Come altro esempio, un percorso ottimale per 2ed 25è

2 -- 4 -- 8 -- 40 -- 200 -- 25

quindi l'output corretto è 5. In questo caso, nessun percorso ottimale contiene il nodo 50 = lcm(2, 25).

Regole e punteggio

È possibile scrivere un programma completo o una funzione. Vince il conteggio di byte più basso e non sono consentite scappatoie standard. Non ci sono limiti di tempo o di memoria, quindi è consentita la forzatura bruta.

Casi test

2 2 -> 0
2 3 -> 4
2 4 -> 1
2 5 -> 5
3 5 -> 4
6 8 -> 2
8 16 -> 1
12 16 -> 2
16 16 -> 0
2 25 -> 5
3 32 -> 4
2 256 -> 3
60 77 -> 3
56 155 -> 3
339 540 -> 2
6 966 -> 4
7 966 -> 2
11 966 -> 4
2 997 -> 7
991 997 -> 4

ho un'idea che non è una forza bruta come immaginavo, conta il multiplo più piccolo di due numeri, moltiplica gradualmente per la potenza due fino a quando appare, quindi si divide gradualmente per il sqrt fino a quando appare il secondo numero, non ho tempo per implementare ora anche se: /
Abr001am

Zgarb, Mathematica FindShortestPath viola il vincolo delle scappatoie standard? In tal caso, fammelo sapere e cancellerò la mia richiesta.
DavidC,

@DavidC Non lo considero una scappatoia. La risposta pertinente ha effettivamente un punteggio di 0.
Zgarb,

Risposte:


4

Matlab, 218 190 175 byte

function f(a,b);q=a;l(b)=0;l(a)=1;while~l(b);x=q(1);q=q(2:end);l(end+1:x^2)=0;g=x+1:x^2;s=2:x-1;u=[g(~mod(g,x)),s(~mod(x,s)&s.^2>=x)];u=u(~l(u));q=[q,u];l(u)=l(x)+1;end;l(b)-1

Grazie @beaker per il collegamento nella fase di allungamento dell'elenco!

Questa è un'implementazione di Dijkstra relativamente semplice:

q=a;                  %queue
l(b)=0;       %list of path lengths
l(a)=1;
while~l(b);         %if there is no predecessor to b
    x=q(1);         %get first queue element
    q=q(2:end);
    %add edges 
    l(end+1:x^2)=0;% lengthen predecessor list if too short
    g=x+1:x^2;      % g=greater neighbours
    s=2:x-1;        % s=smaller neighbours %keep only valid/unvisited neighbours 
    u=[g(~mod(g,x)),s(~mod(x,s)&s.^2>=x)]; %-1byte
    u=u(~l(u));
    q=[q,u];      %add only hte valid nodes edges to queue
    l(u)=l(x)+1;       %mark x as predecessor  
end;
l(b)-1 %output length to the end of the path

nessuna convoluzione oggi


2
Invece di l=zeros(1,a*b);te puoi usare l(a*b)=0;, il che fa lo stesso
Luis Mendo,

ahimè .... ancora 10 byte dietro di te.
Abr001,

1

JavaScript (ES6), 186 byte

(m,n)=>(g=i=>{for(q=[i],r=[],r[i]=j=0;i=q[j++];)for(k=i+i;k<=i*i&(k<m*m*2|k<n*n*2);k+=i)r[k]-r[i]<2?0:r[q.push(k),k]=r[i]+1},g(m),s=r,g(n),Math.min(...r.map((i,j)=>i+s[j]).filter(i=>i)))

Utilizza una funzione di supporto gper calcolare tutti i percorsi ascendenti da me nverso l'alto fino al limite fornito, quindi somma i percorsi insieme e restituisce il valore più basso.


1

Mathematica 98 byte

Presumo che la funzione integrata FindShortestPathnon violi il vincolo di scappatoie standard. In tal caso, fammelo sapere e cancellerò questo invio.

Forza bruta, quindi lenta con grandi valori di b. Sto ancora pensando ai modi per accelerarlo.

h@{a_,b_}:=Length@FindShortestPath[Graph[Apply[Join,Thread[#<->Range[2,#] #]&/@Range[b^2]]],a,b]-1

Questo imposta un grafico con i bordi appropriati tra i nodi da aa b^2. FindShortestPathtrova il percorso più breve nel grafico. Lengthconta i nodi; Length -1è il numero di spigoli.

Thread[# <-> Range[2, #] #] &produce i bordi del grafico completo. Ad esempio, Thread[# <-> Range[2, #] #]&[5]produrrebbe i bordi {5 <-> 2*5, 5 <-> 3*5, 5 <-> 4*5, 5 <-> 5*5}, cioè {5 <-> 10, 5 <-> 15, 5 <-> 20, 5 <-> 25}.


1

Matlab (195) (185) (181) (179)(173)

Nota: io l'utente Agawa001 personalmente attesto che ho vinto l'utente @flawr facendo uso della sua assistenza

 function t(a,b,p),for r=0:1,d=(b*~r+r*a)/gcd(a,b);while(d>1)p=p+1;e=find(~rem(d,1:d));f=max(e(a^(1-r/2)>=e));a=a*min([find(1:a*a>=b) a])^~(f-1);d=d/f;a=a*f^(1-2*r);end,end,p
  • Questa funzione è diversa da quella degli altri, segue un sacco di calcoli matematici puri e fattorizzazioni, ma non ha nulla a che fare con percorsi o grafici.
  • Esempio di chiamata di funzione:

     t(2,3,0)
    
     p =
    
     4
    

    Tutti i casi di test sono soddisfatti

  • Spiegazione:

Prima di iniziare con le spiegazioni, proviamo alcuni lemmi "non verdi":

Lemma (1):(a,b) esiste un percorso ottimale tra due numeri qualsiasi in un modo in cui i nodi inizialmente aumentano e poi diminuiscono.

Perché ? Questo è semplicemente dimostrato perché la quantità intera massima che divide un numero aè rispettivamente grande quanto il numero astesso, quindi come approccio intelligente dobbiamo scegliere di moltiplicare ail più possibile per renderlo sufficientemente più grande, quindi dividendolo per valori più grandi. Se mai facciamo il giro, il numero si ariduce, quindi abbiamo bisogno inutilmente di più iterazioni per moltiplicarlo gradualmente di cui ci siamo dispensati.

Lemma (2): Da un numero aa b, se gcd(a,b)=1 aviene moltiplicato per b, se bè maggiore di aquanto verrà moltiplicato per un numero noto c, se gcd>1 adeve essere moltiplicato gradualmente dal più grande divisore di b/gcdnome dche verifica la condizione a >= danche quando tutto dè precisamente il il minimo è maggiore di a, ariceve di a*cnuovo.

Questa ipotesi è semplice per dimostrare che qualsiasi nodo iniziale adeve essere moltiplicato fino a raggiungere il multiplo più piccolo di ae bquindi o moltiplichiamo per proporzioni di b*gcdinizio per il massimo che verifica la condizione principale, che garantisce sempre il percorso più breve per smp prima che inizi il processo di divisione, o quando dnon è disponibile un numero cviene moltiplicato aper creare una condizione valida a>=dper questo primo stadio.

Lemma (3): da un multiplo del grafico-ultimum di aa b, il gcd di questo numero ed bè esso bstesso

Bene, questa è solo una conseguenza delle precedenti manipolazioni e anche gli ultimi passaggi rimanenti vengono gradualmente divisi dal più grande divisore che non supera la sua radice quadrata.

Dilemma: qual è il numero ottimale cda moltiplicare iterativamente ache porterebbe direttamente alla condizione di apertura per la fase 1 e l'ultimum?

Buona domanda, per ogni semplice situazione c'è una semplice parata, quindi assumendo un esempio di due fini (a,b)=(4,26)fattorizzati in questo modo:

  2 | 2
  2 | 13

A parte gcd=2il numero intero più piccolo che deve essere moltiplicato 2per raggiungere 13è 7, ma è ovviamente escluso, perché è più grande di 2, quindi a è quadrato.

  2 | 2 
  5 | 13

Appearenlty nel secondo esempio (a,b)=(10,26)sopra cè misurato come numero intero più basso da 1a 5che supera 13/5quindi soddisfa la condizione di grafico-scaling, che è 3, quindi il passo successivo è qui moltiplicando per3

  2 | 2 
  5 | 13
  3 |

Perché ? questo perché, una volta che dobbiamo moltiplicare 2*13/gcd=13per abbinare il secondo lato della tabella, la quantità di spazzatura che abbiamo aggiunto prima è in modo ottimale più piccolo e lo spostamento lungo il grafico è ridotto al minimo, se mai abbiamo moltiplicato per un valore più grande come 10la possibilità di dividere per il minor numero di volte si riduce e sarebbe stato aumentato di 1 altro gradino di divisione per raggiungere il nostro obiettivo 2*13. che sono elencati in: 13*2*5*10/2*5then 13*2*5/5. Mentre, ovviamente, qui il numero da dividere è5*3<13*2

e un'altra cosa ........ MATITE DI AVE ...


Questi sono i miei risultati comparativi con quelli di @flawr, ma presta attenzione al fatto che ho fatto un limite superiore per l'esecuzione del tempo, tenendo conto dell'algoritmo di Flawr, ci vuole troppo tempo!

È possibile inserire gli intervalli di scansione iniziale e finale come variabili aeb nell'intestazione del codice compilabile online.


Wow, questo è sorprendente. Non mi aspettavo che i percorsi ottimali potessero essere costruiti in modo semplice. In attesa di una spiegazione ...
Zgarb,

@Zgarb ho fatto una spiegazione banale nei commenti al post principale, sarò elaborato quando finirò di giocare a golf, a proposito, che bella sfida unica!
Abr001,

@Zgarb la prova è fresca fuori dal forno !!!!
Abr001,
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.