2010-06-24 10 views
9

Während dies wie Hausaufgaben aussehen mag, versichere ich Ihnen, dass es nicht ist. Es stammt jedoch von einer Hausaufgabe, die ich gemacht habe.Erzeugen eines zufälligen kubischen Graphen mit gleichförmiger Wahrscheinlichkeit (oder weniger)

Nennen wir einen ungerichteten Graphen ohne Kanten "kubisch", wenn jeder Knoten Grad genau drei hat. Bei einer positiven Ganzzahl N möchte ich einen zufälligen kubischen Graphen auf N Knoten erzeugen. Ich hätte gerne, dass es eine einheitliche Wahrscheinlichkeit hat, das heißt, wenn es M kubische Graphen auf N Ecken gibt, ist die Wahrscheinlichkeit, dass jede 1/M ist. Eine schwächere Bedingung, die immer noch in Ordnung ist, ist, dass jeder kubische Graph eine Wahrscheinlichkeit ungleich Null hat.

I fühlen gibt es eine schnelle und intelligente Möglichkeit, dies zu tun, aber bisher war ich erfolglos.

Ich bin ein schlechter Coder, bitte mit diesem schrecklichen Code tragen:

PRE: Kanten = (3 * Knoten)/2, wird Knoten selbst sind die Konstanten so gewählt, dass die Hash-Werke (BIG_PRIME ist größer als Kanten, SMALL_PRIME ist größer als Knoten, LOAD_FACTOR ist klein).

void random_cubic_graph() { 

int i, j, k, count; 
int *degree; 
char guard; 

count = 0; 
degree = (int*) calloc(nodes, sizeof(int)); 

while (count < edges) { 

    /* Try a new edge at random */ 

    guard = 0; 
    i = rand() % nodes; 
    j = rand() % nodes; 

    /* Checks if it is a self-edge */ 

    if (i == j) 
     guard = 1; 

    /* Checks that the degrees are 3 or less */ 

    if (degree[i] > 2 || degree[j] > 2) 
     guard = 1; 

    /* Checks that the edge was not already selected with an hash */ 

    k = 0; 
    while(A[(j + k*BIG_PRIME) % (LOAD_FACTOR*edges)] != 0) { 
     if (A[(j + k*BIG_PRIME) % (LOAD_FACTOR*edges)] % SMALL_PRIME == j) 
      if ((A[(j + k*BIG_PRIME) % (LOAD_FACTOR*edges)] - j)/SMALL_PRIME == i) 
       guard = 1; 
     k++; 
    } 

    if (guard == 0) 
     A[(j + k*BIG_PRIME) % (LOAD_FACTOR*edges)] = hash(i,j); 

    k = 0; 
    while(A[(i + k*BIG_PRIME) % (LOAD_FACTOR*edges)] != 0) { 
     if (A[(i + k*BIG_PRIME) % (LOAD_FACTOR*edges)] % SMALL_PRIME == i) 
      if ((A[(i + k*BIG_PRIME) % (LOAD_FACTOR*edges)] - i)/SMALL_PRIME == j) 
       guard = 1; 
     k++; 
    } 

    if (guard == 0) 
     A[(i + k*BIG_PRIME) % (LOAD_FACTOR*edges)] = hash(j,i); 

    /* If all checks were passed, increment the count, print the edge, increment the degrees. */ 

    if (guard == 0) { 
     count++; 
     printf("%d\t%d\n", i, j); 
     degree[i]++; 
     degree[j]++; 
    } 

} 

Das Problem ist, dass die endgültige Kante, die ausgewählt werden muss, eine Self-Edge sein kann. Das passiert, wenn N - 1 Vertices bereits Grad 3 haben, nur 1 Grad 1. Daher könnte der Algorithmus nicht enden. Außerdem bin ich nicht ganz davon überzeugt, dass die Wahrscheinlichkeit einheitlich ist.

Es gibt wahrscheinlich viel zu verbessern in meinem Code, aber können Sie vorschlagen, einen besseren Algorithmus zu implementieren?

+2

Ich schlage vor, nicht C-Sprache für Graph-Algorithmen zu verwenden, wenn Sie nur ein Anfänger sind. –

+0

Also, stellen Sie Ihren Graphen als quadratische Matrix dar? Übrigens, was ist das Geschäft mit small_prime, big_prime und load_factor? Klingt für mich so, als ob du die Lösung eines anderen kopierst und versuchst, einen Sinn daraus zu machen. –

+2

Es gibt keine quadratische Matrix: A ist ein Vektor der Länge LOAD_FACTOR * Kanten, der die Kanten enthält. Lass uns einfach so tun, als gäbe es eine Blackbox-Funktion is_edge_present (int i, int j), die überprüft, ob die (i, j) -Front bereits ausgewählt wurde. Dieses Code-Snippet macht das, und wenn die Kante nicht ausgewählt wurde, wählt sie es für zukünftige Suchen aus. Ist es nicht ein bisschen unhöflich anzunehmen, dass ich kopiert habe? Das habe ich geschrieben. Es ist kompliziert und chaotisch, aber deshalb gibt es ein Anfänger-Tag. –

Antwort

10

Angenommen, N ist gerade. (Sonst kann es keinen kubischen Graphen auf N Knoten geben).

Sie können folgendes tun:

3N Punkte nehmen und sie in N Gruppen von 3 Punkte je teilen.

Jetzt paaren Sie diese 3N Punkte zufällig (Anmerkung: 3N ist gerade). h. zwei Punkte willkürlich heiraten und 3N/2 Ehen bilden).

Wenn eine Paarung zwischen Gruppe i und Gruppe j besteht, erstellen Sie eine Kante zwischen i und j. Dies ergibt einen Graphen auf N Ecken.

Wenn diese zufällige Paarung keine mehreren Kanten oder Schleifen erzeugt, haben Sie eine kubische Grafik.

Wenn nicht, versuchen Sie es erneut. Dies läuft in der erwarteten linearen Zeit und erzeugt eine gleichmäßige Verteilung.

Hinweis: Alle kubischen Graphen auf N Knoten werden mit dieser Methode generiert (entsprechend Hamishs Kommentaren).

Um dies zu sehen:

Sei G eine kubische Graph auf n Ecken sein.

Die Vertices seien, 1, 2, ... N.

Die drei Nachbarn von j seien A (j), B (j) und C (j).

Für jedes j, konstruiere die Gruppe der geordneten Paare {(j, A (j)), (j, B (j)), (j, C (j))}.

Dies gibt uns 3N geordnete Paare. Wir paaren sie: (u, v) ist gepaart mit (v, u).

Somit kann jede kubische Graph entspricht einer Paarung und umgekehrt ...

Weitere Informationen zu diesem Algorithmus und schnellere Algorithmen finden sich hier: Generating Random Regular Graphs Quickly.

+0

Was passiert, wenn einige "kubische Graphen" fehlen? Was, wenn einige mit einer anderen Methode generiert werden müssen? –

+0

Danke, ich denke, das erledigt meine Frage. Ich werde nur noch ein paar Stunden warten, bis ich deine Antwort akzeptiere, für den Fall, dass es eine noch bessere Lösung gibt! –

+1

@Hamish: Siehe meine Bearbeitung. Alle kubischen Graphen werden erzeugt ... –

2

Warnung: Ich mache viele intuitive, aber vielleicht auch falsche Behauptungen in dieser Antwort. Sie sollten sie definitiv beweisen, wenn Sie diese Idee verwenden möchten.

Aufzählen Cubic Graphs

Wenn sie mit einer zufälligen Auswahl zu tun, ein guter Ausgangspunkt ist, um herauszufinden, wie alle Ihre möglichen Elemente aufzuzählen über. Dies könnte etwas von der Struktur offenbaren und Sie zu einem Algorithmus führen.

Hier ist meine Strategie zum Aufzählen von kubischen Graphen: Wählen Sie den ersten Eckpunkt und iterieren Sie über alle möglichen Auswahlmöglichkeiten von drei benachbarten Eckpunkten. Wiederholen Sie während dieser Iterationen den nächsten Scheitelpunkt mit der Einschränkung, dass Sie verfolgen, wie viele Kanten erforderlich sind, damit jeder Scheitelpunktgrad 3 erreicht. Fahren Sie auf diese Weise fort, bis die unterste Ebene erreicht ist. Jetzt haben Sie Ihre erste kubische Grafik. Machen Sie die zuletzt hinzugefügten Kanten rückgängig und fahren Sie mit der nächsten Möglichkeit fort, bis keine mehr übrig sind. Es gibt einige Implementierungsdetails, die Sie beachten müssen, aber im Allgemeinen unkompliziert.

Generalize Enumeration in Wahl

Wenn Sie alle Elemente aufzählen kann, ist es trivial, eine zufällige Wahl zu treffen. Beispielsweise können Sie die Liste einmal scannen, um ihre Größe zu berechnen, dann eine Zufallszahl in [0, Größe] auswählen und dann die Sequenz erneut scannen, um das Element an diesem Offset zu erhalten. Dies ist unglaublich ineffizient und dauert MINDESTENS proportional zur O (n^3) Anzahl von kubischen Graphen, aber es funktioniert.

Uniform Wahrscheinlichkeit für Effizienz Opfer

Die offensichtliche Speed-up hier ist zufällig Rand Entscheidungen auf jeder Ebene zu machen, anstatt über jede Möglichkeit, iteriert. Leider wird dies einige Graphen bevorzugen, da Ihre frühen Entscheidungen die Verfügbarkeit späterer Entscheidungen beeinflussen. Unter Berücksichtigung der Notwendigkeit, die verbleibenden freien Knoten zu verfolgen, sollten Sie in der Lage sein, O (n log n) -Zeit und O (n) -Raum zu erreichen. Deutlich besser als der Aufzählungsalgorithmus.

...

Es ist wahrscheinlich möglich, es besser zu machen. Wahrscheinlich viel besser. Aber das sollte dich beginnen.

+0

Dies ist eine interessante allgemeine Strategie, die ich übersehen habe. Ich möchte vielleicht beim nächsten Mal auf diese Strategie zurückgreifen. Vielen Dank! –

+0

Beachten Sie, dass Sie ein Element zufällig aus einer Liste auswählen können, indem Sie es nur einmal scannen, ohne die Größe zuerst berechnen zu müssen: http://en.wikipedia.org/wiki/Reservoir_sampling (let k = 1) – Paulpro

1

Ein anderer Begriff für cubic graph ist 3- regular graph oder dreiwertigen Graph.

Ihr Problem muss ein wenig mehr Klarheit, weil „die Zahl der kubischen Graphen“ könnte die Anzahl der kubischen Graphen auf 2 n Knoten bedeuten, die nicht-isomorph sind zu einem Kubik anderen oder die Anzahl der (nicht-isomorph) Graphen auf 2 n markierten Knoten. Ersteres wird durch die Ganzzahlfolge A005638 gegeben, und es ist wahrscheinlich ein nicht-triviales Problem, eine zufällige Isomorphieklasse von kubischen Graphen effizient einheitlich auszuwählen (d. H. Sie nicht alle aufzulisten und dann eine Klasse auszuwählen). Letzteres ist gegeben durch A002829.

Es gibt einen Artikel auf Wikipedia über random regular graphs, den Sie sich ansehen sollten.

+1

[ Kubische Grafik] (http://en.wikipedia.org/wiki/Cubic_graph) ist ein vollkommen Standardbegriff. –

+0

Danke für die Klarstellung. Ich suche nach 3-regulären Graphen ohne Schleifen an 2n markierten Knoten. Ich muss dich korrigieren: Ich suche nicht nach Mehrfachzahlen, sondern verwerfe eine Kante (i, j), wenn sie bereits ausgewählt wurde. Danke für den Wiki-Link, da er den gleichen Algorithmus der ersten Antwort liefert. –

+0

@BlueRaja - Danny Pflughoeft: In der Tat ist es. Ich muss meine Antwort aktualisieren. –

Verwandte Themen