Numero totale di specie topologiche


11

Per una data DAG (grafo aciclico diretto), ciascuno dei suoi tipi topologici è una permutazione di tutti i vertici, dove per ogni bordi (u, v) nel DAG, u compare prima v nella permutazione.

Il tuo compito è calcolare il numero totale di specie topologiche di un determinato DAG.

Regole

  • È possibile utilizzare qualsiasi formato per rappresentare il grafico, come matrice di adiacenza, elenco di adiacenza o elenco di bordi, purché non si eseguano calcoli utili nella codifica. Puoi anche avere elementi come il conteggio dei vertici o l'elenco dei vertici nell'input, se sono utili.
  • Puoi supporre che il grafico nell'input sia sempre un DAG (non ha alcun ciclo).
  • Il tuo programma dovrebbe funzionare in teoria per qualsiasi input. Ma può fallire se supera il tipo intero di base nella tua lingua.
  • I nomi dei vertici possono essere qualsiasi valore consecutivo in qualsiasi tipo. Ad esempio: numeri che iniziano da 0 o 1. (E solo se non si memorizza il codice in questo numero, ovviamente.)
  • Questo è code-golf. Il codice più corto vince.

Esempio

Questo è lo stesso input in diversi formati. Il tuo programma non deve accettarli tutti. I vertici sono sempre numeri interi che iniziano da 0.

Adjacency list:
[ [1 2 3 5] [2 4] [] [2] [] [3] ]
Adjacency matrix:
[ [0 1 1 1 0 1] [0 0 1 0 1 0] [0 0 0 0 0 0] [0 0 1 0 0 0] [0 0 0 0 0 0] [0 0 0 1 0 0] ]
Edge list:
6 [ [0 1] [0 2] [0 3] [0 5] [1 2] [1 4] [3 2] [5 3] ]

È il grafico mostrato in questa immagine:

Grafico di esempio

L'output dovrebbe essere:

9

I tipi topologici sono:

[0 1 4 5 3 2]
[0 1 5 4 3 2]
[0 1 5 3 4 2]
[0 1 5 3 2 4]
[0 5 1 4 3 2]
[0 5 1 3 4 2]
[0 5 1 3 2 4]
[0 5 3 1 4 2]
[0 5 3 1 2 4]

Funzione? Intero programma? O?
isaacg,

@isaacg O entrambi.
jimmy23013,

Risposte:


4

CJam - 25

q~{_f{1$-_j@j@&!*}_!+:+}j

Con grande aiuto dell'utente23013 :)

Provalo online

Spiegazione:

L'algoritmo generale è lo stesso della soluzione Python di xnor .
La chiave qui è l' joperatore, che esegue la ricorsione memorizzata. Sono necessari un parametro, un valore o un array per i valori iniziali (come in f (0), f (1), ecc.) E un blocco per definire la ricorsione. L' joperatore viene nuovamente utilizzato all'interno del blocco per eseguire chiamate ricorsive (e memorizzate) allo stesso blocco. Può anche essere utilizzato con più parametri, ma non è il caso qui.
La grande innovazione di user23013 consiste nell'utilizzare j con diversi tipi di dati, facendo uso dell'elenco di adiacenza come matrice di valori iniziali.

q~             read and evaluate the input (vertex list followed by adjacency list)
{…}j           run the block on the vertex list, doing memoized recursion
                and using the adjacency list for initial values
    _          copy the vertex list
    f{…}       for each vertex and the vertex list
        1$-    copy the vertex and remove it from the list
                Python: "V-{v}"
        _j     copy the reduced list and call the j block recursively
                this solves the problem for the reduced vertex list
                Python: "f(G,V-{v})"
        @j     bring the vertex to the top of the stack and call the j block recursively
                in this case, it's called with a vertex rather than a list
                and the memoized value is instantly found in the list of initial values
                effectively, this gets the list of vertices adjacent to the current vertex
                Python: "G[v]"
        @&     bring the reduced list to the top of the stack and intersect
        !*     multiply the number of topological sorts of the reduced vertex list
                with 1 if the intersection was empty and 0 if not
                Python: equivalent to "*(V-G[v]==V)"
               after this loop we get an array of sub-results for the reduced vertex lists
    _!+        add 1 or 0 to the array if the array was empty or not
                because we want to get 1 for the empty array
                Python: equivalent to "V<{0}or"
    :+         add the numbers in the array
                Python: "sum(…)"

1
Modificato per consentire esplicitamente l'elenco dei vertici nell'input. Ora 25 byte .
jimmy23013,

@ user23013 Che tipo di stregoneria è questa? : o
aditsu ha smesso perché SE è MALE

7

Python, 58 anni

f=lambda G,V:V<{0}or sum(f(G,V-{v})*(V-G[v]==V)for v in V)

L'input consiste in un dizionario di adiacenza Ge un set di vertici V.

G = {0:{1,2,3,5}, 1:{2,4}, 2:set(), 3:{2}, 4:set(), 5:{3}, 6:set()}
V = {0,1,2,3,4,5}

Il codice è ricorsivo. Il set Vmemorizza tutti i nodi che devono ancora essere visitati. Per ciascun potenziale nodo successivo, controlliamo sua idoneità per vedere se non altri vertici puntano ad esso, con V-G[v]==Vil controllo che Ve G[v]sono disgiunti. Per tutti questi vertici adatti, aggiungiamo il numero di specie topologiche rimosse. Come base, il set vuoto dà 1.


+1 per non usare la edge list.
jimmy23013,

5

Mathematica, 80 57 51 byte

Count[Permutations@#,l_/;l~Subsets~{2}~SubsetQ~#2]&

Implementazione della definizione molto diretta. Sto solo generando tutte le permutazioni e conto quante di esse sono valide. Per verificare se una permutazione è valida, ottengo tutte le coppie di vertici nella permutazione. Convenientemente, Subsets[l,{2}]non solo mi dà tutte le coppie, ma mantiene anche l'ordine in cui si trovano l- proprio quello di cui ho bisogno.

Quanto sopra è una funzione che prevede l'elenco dei vertici e l'elenco dei bordi, come

f[{1, 2, 3, 4, 5, 6}, {{1, 2}, {1, 3}, {1, 4}, {1, 6}, {2, 3}, {2, 5}, {4, 3}, {6, 4}}]

se si chiama la funzione f.

Proverò a giocare a golf o forse userò un altro approccio in seguito.


2

Pyth, 27 byte

Mlf!sm}_dHfq2lYyTfqSZUZ^UGG

Definisce una funzione 2 di ingresso, g. Il primo input è il numero di vertici, il secondo è l'elenco dei bordi diretti.

Testare:

Code:
Mlf!sm}_dHfq2lYyTfqSZUZ^UGGghQeQ

Input:
6, [ [0, 1], [0, 2], [0, 3], [0, 5], [1, 2], [1, 4], [3, 2], [5, 3] ]

Provalo qui.


@ user23013 Il conteggio e l'elenco di Boht vengono utilizzati, nell'espressione ^UGG, che genera tutti gli Gelenchi di voci di range(len(G)).
isaacg,

Volevo dire, sarà più breve se si utilizza [0, 1, ...]direttamente nell'input?
jimmy23013,

@ user23013 No, sarebbe la stessa lunghezza: ^GlGcontro ^UGG.
isaacg,

2

Haskell, 102 107 100 89 85 byte

import Data.List
(%)=elemIndex
n#l=sum[1|p<-permutations[0..n],and[u%p<v%p|[u,v]<-l]]

L'input è il numero di vertice più alto (che inizia con 0) e un elenco di bordi, in cui un bordo è un elenco di due elementi. Esempio di utilizzo:5 # [[0,1], [0,2], [0,3], [0,5], [1,2], [1,4], [3,2], [5,3]]

Come funziona: conta tutte le permutazioni pdei vertici per cui tutti i bordi [u,v]soddisfano: la posizione di uin pè inferiore alla posizione di vin p. Questa è un'implementazione diretta della definizione.

Modifica: la mia prima versione ha restituito gli stessi tipi topologici e non quanti ce ne sono. Aggiustato.

Modifica II: non ha funzionato per i grafici con vertici non collegati. Aggiustato.


Sto pensando di aggiungere un test case con solo vertici ma non bordi ...
jimmy23013,

@ user23013: ora funziona per grafici con vertici non collegati. È persino diventato più breve.
nimi,
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.