2010-06-24 11 views
9

Mentre questo può sembrare un compito a casa, ti assicuro che non lo è. Deriva da alcuni compiti a casa che ho fatto, però.Generazione di un grafico cubico casuale con probabilità uniforme (o inferiore)

Chiamiamo un grafico non orientato senza bordi "cubici" se ogni vertice ha esattamente il grado tre. Dato un numero intero positivo N Mi piacerebbe generare un grafico cubico casuale su N vertici. Mi piacerebbe che avesse una probabilità uniforme, cioè se ci sono grafici cubici M su N vertici la probabilità di generare ciascuno è 1/M. Una condizione più debole che è ancora valida è che ogni grafico cubico ha una probabilità diversa da zero.

I feel c'è un modo rapido e intelligente per farlo, ma finora non ho avuto successo.

Io sono un cattivo codificatore, si prega di tenere con questo codice terribile:

PRE: bordi = (3 * nodi)/2, i nodi è pari, le costanti sono selezionati in modo tale che i lavori di hash (BIG_PRIME è più grande dei bordi, SMALL_PRIME è più grande dei nodi, LOAD_FACTOR è piccolo).

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]++; 
    } 

} 

Il problema è che il suo ultimo bordo che deve essere selezionato potrebbe essere un vantaggio. Ciò accade quando i vertici N-1 hanno già grado 3, solo 1 ha il grado 1. Quindi l'algoritmo potrebbe non terminare. Inoltre, non sono del tutto convinto che la probabilità sia uniforme.

Probabilmente c'è molto da migliorare nel mio codice, ma puoi suggerire un algoritmo migliore da implementare?

+2

Io suggerisco di non usare il linguaggio C per gli algoritmi del grafico quando sei solo un principiante. –

+0

Quindi, stai rappresentando il tuo grafico come una matrice quadrata? A proposito, cos'è questa attività small_prime, big_prime e load_factor? Mi sembra che tu abbia copiato la soluzione di qualcun altro e stia cercando di dare un senso a ciò. –

+2

Non esiste una matrice quadrata: A è un vettore di lunghezza LOAD_FACTOR * i bordi che contengono i bordi. Facciamo finta che esista una funzione blackbox is_edge_present (int i, int j) che controlla se il bordo (i, j) era già selezionato. Quel frammento di codice lo fa, e se il bordo non è selezionato lo seleziona per ricerche future. Non è un po 'scortese presumere di averlo copiato? L'ho scritto È complicato e disordinato, ma è per questo che c'è un tag per principianti. –

risposta

10

Assumere N è pari. (Altrimenti non ci può essere un grafico cubico su N vertici).

È possibile effettuare le seguenti operazioni:

Prendere punti 3N e dividerli in N gruppi di 3 punti ciascuno.

Ora accoppiare questi 3 punti in modo casuale (nota: 3N è pari). cioè sposare due punti a caso e formare 3N/2 matrimoni).

Se è presente un'associazione tra il gruppo i e il gruppo j, creare un bordo tra i e j. Questo dà un grafico su N vertici.

Se questo abbinamento casuale non crea più spigoli o loop multipli, si dispone di un grafico cubico.

Se non riprovare. Questo funziona nel tempo lineare previsto e genera una distribuzione uniforme.

Nota: tutti i grafici cubici su N vertici sono generati da questo metodo (in risposta ai commenti di Hamish).

Per vedere questo:

Sia G un grafo cubico su N vertici.

Lasciate che i vertici siano, 1, 2, ... N.

Lasciate che i tre vicini di j siano A (j), B (j) e C (j).

Per ogni j, costruire il gruppo di coppie ordinate {(j, A (j)), (j, B (j)), (j, C (j))}.

Questo ci dà coppie ordinate 3N. Li accoppiamo: (u, v) è accoppiato con (v, u).

Pertanto, qualsiasi grafo cubico corrisponde ad un accoppiamento e viceversa ...

Ulteriori informazioni su questo algoritmo e algoritmi più veloci possono essere trovate qui: Generating Random Regular Graphs Quickly.

+0

Cosa succede se questo manca alcuni "grafici cubici"? Cosa succede se alcuni devono essere generati usando qualche altro metodo? –

+0

Grazie, penso che questo risolva la mia domanda. Aspetterò solo qualche ora prima di accettare la tua risposta nel caso ci sia una soluzione ancora migliore in arrivo! –

+1

@Hamish: vedere la mia modifica. Tutti i grafici cubici sono generati ... –

2

Avvertenza: in questa risposta faccio molte affermazioni intuitive, ma forse errate. Dovresti assolutamente provarli se hai intenzione di usare questa idea.

enumerazione grafo cubico

Quando si tratta di una scelta casuale, un buon punto di partenza è quello di capire come enumerare su tutti i possibili elementi. Questo potrebbe rivelare parte della struttura e portarti ad un algoritmo.

Ecco la mia strategia per enumerare i grafici cubici: selezionare il primo vertice e scorrere su tutte le possibili scelte di tre vertici adiacenti. Durante quelle iterazioni, recita sul prossimo vertice, con l'avvertenza che tieni traccia di quanti spigoli sono necessari per raggiungere ogni grado di vertice 3. Continui in quel modo fino a raggiungere il livello più basso. Ora hai il tuo primo grafico cubico. Annulla i bordi aggiunti di recente e continua fino alla prossima possibilità finché non ne rimane nessuno. Ci sono alcuni dettagli di implementazione che è necessario considerare, ma in generale semplici.

Generalizza Enumeration in Scelta

Una volta che è possibile enumerare tutti gli elementi, è banale per fare una scelta casuale. Ad esempio, è possibile scansionare l'elenco una volta per calcolarne le dimensioni, quindi selezionare un numero casuale in [0, dimensione], quindi eseguire di nuovo la scansione della sequenza per ottenere l'elemento in corrispondenza di tale offset. Questo è incredibilmente inefficiente, prendendo ALMENO tempo proporzionale al numero O (n^3) di grafici cubici, ma funziona.

Sacrifica probabilità uniforme per l'efficienza

L'accelerazione è qui per fare scelte bordo casuale ad ogni livello, invece di iterare su ogni possibilità ovvia. Sfortunatamente, ciò favorirà alcuni grafici a causa di come le tue scelte iniziali influenzano la disponibilità delle scelte successive. Tenendo conto della necessità di tracciare i restanti vertici liberi, dovresti essere in grado di ottenere il tempo O (n log n) e lo spazio O (n). Significativamente migliore dell'algoritmo di enumerazione.

...

E 'probabilmente possibile fare meglio. Probabilmente molto meglio. Ma questo dovrebbe iniziare.

+0

Questa è un'interessante strategia generale che ho trascurato. Potrei voler ricorrere a questa strategia la prossima volta. Grazie! –

+0

Si noti che è possibile selezionare un elemento in modo uniforme a caso da un elenco scansionandolo solo una volta, non è necessario calcolare prima la dimensione: http://en.wikipedia.org/wiki/Reservoir_sampling (let k = 1) – Paulpro

1

altro termine per cubic graph è 3- regular graph o grafico trivalente.

Il vostro problema ha bisogno di un po 'più di un chiarimento, perché "il numero di grafici cubi" potrebbe significare il numero di grafici cubi su 2 n nodi che non sono isomorfi tra loro o il numero di (non isomorfi) cubica grafici su 2 n nodi etichettati. Il primo è dato dalla sequenza intera A005638, ed è probabile che un problema non banale sia quello di selezionare in modo univoco una classe di isomorfismi casuali di grafici cubici in modo efficiente (cioè non elencarli tutti e quindi selezionare una classe). Quest'ultimo è dato da A002829.

C'è un articolo su Wikipedia su random regular graphs che dovresti dare un'occhiata a.

+1

[ Il grafico cubico] (http://en.wikipedia.org/wiki/Cubic_graph) è un termine perfettamente standard. –

+0

Grazie per il chiarimento. Sto cercando il grafico 3-regular senza loop su nodi con etichetta 2n. Devo correggerti: non sto cercando le multi-poligonali, infatti scarterei un vantaggio (i, j) se è già stato selezionato. Grazie per il link wiki, poiché fornisce lo stesso algoritmo della prima risposta. –

+0

@BlueRaja - Danny Pflughoeft: In effetti lo è. Devo aggiornare la mia risposta. –

Problemi correlati