Kürzeste Pfade in einem Divisor-Diagramm

15

Einführung

In dieser Herausforderung werden wir uns mit einem bestimmten unendlichen ungerichteten Graphen befassen, den ich den Hochteiler-Graphen nenne . Seine Knoten sind die ganzen Zahlen ab 2. Es gibt eine Kante zwischen zwei Knoten a <b, wenn a b und a 2 ≥ b teilt . Der durch den Bereich von 2 bis 18 gebildete Teilgraph sieht folgendermaßen aus:

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

Es kann gezeigt werden, dass der unendliche Hochteilergraph verbunden ist, sodass wir nach dem kürzesten Weg zwischen zwei Knoten fragen können.

Ein- und Ausgabe

Ihre Eingaben sind zwei ganze Zahlen a und b . Sie können annehmen, dass 2 ≤ a ≤ b <1000 ist . Ihre Ausgabe ist die Länge des kürzesten Pfades zwischen a und b im unendlichen Hochdivisor-Diagramm. Dies bedeutet die Anzahl der Kanten im Pfad.

Möglicherweise ist die folgende Tatsache hilfreich: Es gibt immer einen optimalen Pfad von a nach b , der zuerst zunimmt und dann abnimmt, und es werden nur Knoten besucht, die strikt kleiner als 2b 2 sind . Da b <1000 ist, müssen Sie insbesondere nur Knoten mit weniger als 2 000 000 berücksichtigen.

Beispiele

Betrachten Sie die Eingänge 3und 32. Ein möglicher Weg zwischen den Knoten 3 und 32 ist

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

Dieser Pfad hat vier Kanten und es stellt sich heraus, dass es keine kürzeren Pfade gibt. Daher ist die Ausgabe korrekt 4.

Als weiteres Beispiel wird ein optimaler Weg für 2und 25ist

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

also die richtige ausgabe ist 5. In diesem Fall enthält kein optimaler Pfad den Knoten 50 = lcm(2, 25).

Regeln und Wertung

Sie können ein vollständiges Programm oder eine Funktion schreiben. Die niedrigste Byteanzahl gewinnt, und Standardlücken sind nicht zulässig. Es gibt keine Zeit- oder Speicherbeschränkungen, daher ist Brute Forcing zulässig.

Testfälle

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
Zgarb
quelle
Ich habe eine Idee, die keine rohe Kraft ist, wie ich angenommen habe, sie zählt das kleinste Vielfache von zwei Zahlen, multipliziert allmählich mit der Potenz zwei, bis sie erscheint, und dividiert allmählich durch den Quadrat, bis die zweite Zahl erscheint. Ich habe keine Zeit um iy jetzt zu implementieren, obwohl: /
Abr001am
Zgarb, FindShortestPath verstößt Mathematica gegen die Vorgabe von Standardlücken? Wenn ja, lass es mich einfach wissen und ich werde meinen Beitrag löschen.
DavidC
@ DavidC Ich halte es nicht für eine Lücke. Die relevante Antwort hat tatsächlich eine Punktzahl von 0.
Zgarb

Antworten:

4

Matlab, 218 190 175 Bytes

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

Vielen Dank an @beaker für die Verknüpfung im Schritt zur Listenverlängerung!

Dies ist eine relativ einfache dijkstra-Implementierung:

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

Keine Faltung heute

fehlerhaft
quelle
2
Stattdessen l=zeros(1,a*b);kannst du verwenden l(a*b)=0;, was das gleiche tut
Luis Mendo
leider .... noch 10 Bytes lang hinter dir.
13.
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)))

Verwendet eine Hilfsfunktion g, um alle aufsteigenden Pfade von mund nbis zum angegebenen Grenzwert zu berechnen , summiert dann die Pfade und gibt den niedrigsten Wert zurück.

Neil
quelle
1

Mathematica 98 Bytes

Ich gehe davon aus, dass die eingebaute Funktion FindShortestPathnicht gegen die Einschränkung über Standard-Regelungslücken verstößt. Wenn ja, lass es mich einfach wissen und ich werde diese Einsendung löschen.

Brute Force, daher langsam mit großen Werten von b. Ich denke immer noch über Möglichkeiten nach, es zu beschleunigen.

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

Dadurch wird ein Diagramm mit den entsprechenden Kanten zwischen den Knoten von abis erstellt b^2. FindShortestPathfindet den kürzesten Weg in der Grafik. Lengthzählt die Knoten; Length -1ist die Anzahl der Kanten.

Thread[# <-> Range[2, #] #] &Erzeugt die Kanten des vollständigen Graphen. Zum Beispiel Thread[# <-> Range[2, #] #]&[5]würde die Kanten erzeugen {5 <-> 2*5, 5 <-> 3*5, 5 <-> 4*5, 5 <-> 5*5}, das heißt {5 <-> 10, 5 <-> 15, 5 <-> 20, 5 <-> 25}.

DavidC
quelle
1

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

Hinweis: Ich persönlich, der Benutzer Agawa001, bestätige, dass ich den Benutzer @flawr von seiner Unterstützung überzeugt habe

 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
  • Diese Funktion unterscheidet sich von anderen, sie folgt einer Reihe von rein mathematischen Berechnungen und Faktorisierungen, hat jedoch nichts mit Pfaden oder Graphen zu tun.
  • Beispiel eines Funktionsaufrufs:

     t(2,3,0)
    
     p =
    
     4
    

    Alle Testfälle sind erfüllt

  • Erläuterung:

Bevor wir mit Erklärungen beginnen, wollen wir einige Lemmas "nicht grüne" beweisen:

Lemma (1): Ein optimaler Weg zwischen zwei beliebigen Zahlen (a,b)besteht darin, dass die Knoten zuerst zunehmen und dann abnehmen.

Warum ? Dies ist einfach bewiesen, weil der maximale ganzzahlige Betrag, der eine Zahl dividiert, ajeweils so groß ist wie die Zahl aselbst. Als kluger Ansatz müssen wir aso viel wie möglich multiplizieren , um sie ausreichend zu vergrößern, und dann durch größere Werte dividieren. Wenn wir jemals den umgekehrten Weg gehen, wird die Zahl akleiner, sodass wir unnötig mehr Iterationen benötigen, um sie allmählich zu multiplizieren, ohne dass wir darauf verzichten müssen.

Lemma (2): Von einer Zahl azu b, wenn gcd(a,b)=1 amultipliziert mit b, wenn bgrößer als aes ist, wird multipliziert mit einer bekannten Zahl c, wenn nach gcd>1 aund nach multipliziert werden muss mit dem größten Divisor von b/gcdnamed d, der die Bedingung a >= dauch dann überprüft, wenn alles ddas ist Minimum sind größer als a, aerhält a*cwieder.

Diese Annahme ist einfach zu beweisen, dass jeder Startknoten amultipliziert werden muss, bis er das kleinste Vielfache von erreicht, aund bdaher multiplizieren wir entweder mit den Anteilen des b*gcdAnfangs mit dem Maximum, was die Hauptbedingung verifiziert, die immer den kürzesten Weg zu smp garantiert, bevor der Divisionsprozess beginnt. oder wenn dnicht verfügbar, wird eine Zahl cmit multipliziert a, um eine gültige Bedingung a>=dfür diese erste Stufe zu erstellen .

Lemma (3): Aus einem graphen ultimum mehr von azu b, den GCD dieser Zahl und bist bselbst

Nun, dies ist nur eine Folge der vorherigen Manipulationen, und die letzten verbleibenden Schritte werden auch schrittweise durch den größten Teiler geteilt, der seine Quadratwurzel nicht überschreitet.

Dilemma: Was ist die optimale Zahl c, die iterativ multipliziert werden muss a, um direkt zur Eröffnungsbedingung für Stufe 1 und dann zum Ultimum zu gelangen?

Gute Frage, für jede einfache Situation gibt es eine einfache Parade. Nehmen wir also ein Beispiel von zwei Enden an, die (a,b)=(4,26)wie folgt faktorisiert sind:

  2 | 2
  2 | 13

Neben der gcd=2kleinsten ganzen Zahl Weicht durch multiplizieren müssen , 2um zu erreichen 13ist 7, aber es ist offensichtlich ausgeschlossen, Cuz es größer als 2 ist, so dass ein Quadrat ist.

  2 | 2 
  5 | 13

Das Aussehen im (a,b)=(10,26)obigen zweiten Beispiel cwird als die niedrigste ganze Zahl gemessen 1, 5die übersteigt, 13/5und erfüllt daher die Bedingung der Graphskalierung, dh 3, der nächste Schritt ist hier das Multiplizieren mit3

  2 | 2 
  5 | 13
  3 |

Warum ? Dies liegt daran, dass, sobald wir mit multiplizieren müssen 2*13/gcd=13, um der zweiten Seite der Tabelle zu entsprechen, der zuvor hinzugefügte Junk-Betrag optimal klein ist und die Bewegung entlang des Diagramms minimiert wird, wenn wir jemals mit einem höheren Wert multipliziert werden, beispielsweise 10der Chance, durch zu dividieren Die kürzeste Zeit verkürzt sich, und sie wäre um einen weiteren Teilungsschritt erhöht worden, um unser Ziel zu erreichen 2*13. welche sind aufgezählt: 13*2*5*10/2*5dann 13*2*5/5. Dabei ist hier offensichtlich die zu teilende Zahl5*3<13*2

und noch eins ........ HAIL MATHS ...


Dies sind meine Vergleichsergebnisse mit denen von @flawr. Achten Sie nur darauf, dass ich eine Obergrenze für die Zeitausführung festgelegt habe, wobei der Algorithmus von flawr berücksichtigt wird. Es dauert zu lange!

Sie können den Start- und End-Scanbereich als Variablen a und b in die Kopfzeile des online kompilierbaren Codes einfügen.

Abr001am
quelle
Wow, das ist überraschend. Ich hätte nicht erwartet, dass optimale Wege auf einfache Weise konstruiert werden können. Ich freue mich auf die Erklärung ...
Zgarb
@Zgarb Ich habe in den Kommentaren des Hauptpostens eine triviale Erklärung abgegeben. Ich werde es genauer erläutern, wenn ich mit dem Golfen fertig bin. Übrigens, was für eine einzigartige Herausforderung!
Ab
@Zgarb der Beweis ist frisch aus dem Ofen !!!!
13.