Trova il numero cromatico


13

Sorprendentemente, non abbiamo ancora avuto problemi con la colorazione dei grafici!

Dato un grafico non orientato, possiamo dare a ciascun vertice un colore in modo tale che due vertici adiacenti non condividano lo stesso colore. Il numero più piccolo χ di colori distinti necessari per raggiungere questo obiettivo è chiamato numero cromatico del grafico.

Ad esempio, quanto segue mostra una colorazione valida utilizzando il numero minimo di colori:

(Trovato su Wikipedia)

Quindi il numero cromatico di questo grafico è χ = 3 .

Scrivi un programma o una funzione che, dato un numero di vertici N <16 (che sono numerati da 1 a N ) e un elenco di spigoli, determina il numero cromatico di un grafico.

È possibile ricevere l'input e produrre l'output in qualsiasi formato conveniente, purché l'input non sia pre-elaborato. Cioè, puoi usare una stringa o un array, aggiungere comodi delimitatori alla stringa o usare un array nidificato, ma qualunque cosa tu faccia, la struttura appiattita dovrebbe contenere gli stessi numeri degli esempi seguenti (nello stesso ordine).

Non è possibile utilizzare funzioni correlate alla teoria dei grafi incorporate (come quelle di Mathematica ChromaticNumber).

Si può presumere che il grafico non abbia un ciclo (un bordo che collega un vertice con se stesso) in quanto ciò renderebbe il colore incolore.

Questo è il codice golf, vince la risposta più breve (in byte).

Esempi

Il tuo programma deve almeno risolverli tutti in un ragionevole lasso di tempo. (Deve risolvere correttamente tutti gli input, ma potrebbe richiedere più tempo per input più grandi.)

Per abbreviare il post, nei seguenti esempi, presento i bordi in un unico elenco separato da virgole. È possibile invece utilizzare le interruzioni di riga o aspettarsi l'input in un formato dell'array conveniente, se si preferisce.

Triangolo (χ = 3)

3
1 2, 2 3, 1 3

"Ring" di 6 vertici (χ = 2)

6
1 2, 2 3, 3 4, 4 5, 5 6, 6 1

"Ring" di 5 vertici (χ = 3)

5
1 2, 2 3, 3 4, 4 5, 5 1

Immagine di esempio sopra (χ = 3)

6
1 2, 2 3, 3 4, 4 5, 5 6, 6 1, 1 3, 2 4, 3 5, 4 6, 5 1, 6 2

Generalizzazione di quanto sopra per 7 vertici (χ = 4)

7
1 2, 2 3, 3 4, 4 5, 5 6, 6 7, 7 1, 1 3, 2 4, 3 5, 4 6, 5 7, 6 1, 7 2

Grafico di Petersen (χ = 3)

10
1 2, 2 3, 3 4, 4 5, 5 1, 1 6, 2 7, 3 8, 4 9, 5 10, 6 8, 7 9, 8 10, 9 6, 10 7

Grafico completo di 5 vertici, più vertice disconnesso (χ = 5)

6
1 2, 1 3, 1 4, 1 5, 2 3, 2 4, 2 5, 3 4, 3 5, 4 5

Grafico completo di 8 vertici (χ = 8)

8
1 2, 1 3, 1 4, 1 5, 1 6, 1 7, 1 8, 2 3, 2 4, 2 5, 2 6, 2 7, 2 8, 3 4, 3 5, 3 6, 3 7, 3 8, 4 5, 4 6, 4 7, 4 8, 5 6, 5 7, 5 8, 6 7, 6 8, 7 8

Reticolo triangolare con 15 vertici (χ = 3)

15
1 2, 1 3, 2 3, 2 4, 2 5, 3 5, 3 6, 4 5, 5 6, 4 7, 4 8, 5 8, 5 9, 6 9, 6 10, 7 8, 8 9, 9 10, 7 11, 7 12, 8 12, 8 13, 9 13, 9 14, 10 14, 10 15, 11 12, 12 13, 13 14, 14 15

Potresti definire ragionevole? 1 minuto? 10?
ThreeFx,

@ThreeFx sì, 10 minuti sono ragionevoli. mezza giornata non lo è. Non voglio essere troppo rigoroso al limite, perché poi devo testare di nuovo tutto sulla stessa (mia) macchina. ma diciamo che se si completa entro un'ora sulla tua macchina va bene.
Martin Ender,

Risposte:


4

Python 2.7 - 122 109 111 109 108 103

f=lambda n,e,m=1:any(all(t*m//m**a%m!=t*m//m**b%m for(a,b)in e)for t in range(m**n))and m or f(n,e,m+1)

Uso:

print f(5, [(1, 2), (2, 3), (3, 4), (4, 5), (5, 1)])

Forza bruta aumentando il numero cromatico (m) e controllare tutti i possibili coloranti. Una colorazione può essere descritta come un numero in base m. Quindi i possibili coloranti sono 0, 1, ..., m ^ n-1.

modifica: il grafico completo di 8 vertici richiede abbastanza tempo. Ma il mio laptop lo risolve in circa 10 minuti. Gli altri casi di test impiegano solo pochi secondi.


modifica 2: Leggi che è consentita la preelaborazione, quindi lascio che l'indice dei vertici inizi con 0: accorcia t * m // m ** x% m a t // m ** a% m (-2). Sciogli la lambda e metti m in parametri di funzione (-11)


modifica 3: la preelaborazione non è consentita -> torna a t * m (+4), semplificata // a / (-2).


modifica 4: rimuovi le parentesi quadre in qualsiasi (-2), grazie xnor.


modifica 5: invece di prendere due volte modulo m, sottraggili e successivamente usa modulo (-1). Anche questo è un miglioramento delle prestazioni. Tutti i test insieme richiedono circa 25 secondi sul mio laptop.


modifica 6: chiamata ricorsiva anziché mentre 1: e m + = 1 (-5). Grazie ancora, xnor.


Bel metodo. Un semplice golf: puoi rimuovere le parentesi quadre all([...])se racchiudi a,bin parentesi (che non costa caratteri qui a causa della spaziatura) in modo che allnon li confondano per argomenti aggiuntivi. Inoltre, sospetto che tu possa salvare i caratteri se ti impegni con una chiamata di funzione al successivo più alto minvece di usare un ciclo while.
xnor,

Grazie, l'approccio ricorsivo richiede +2 caratteri. Un approccio anche per m in range (n + 1).
Jakube,

Ho ottimizzato il metodo ricorsivo un po 'con anye il and/ortrucco, e poi si salva alcuni caratteri: f=lambda n,e,m=1:any(all(t*m//m**a%m!=t*m//m**b%m for(a,b)in e)for t in range(m**n))and m or f(n,e,m+1).
xnor

2

Java - 241 218

int k,j,c;int f(int n,int[]e){for(k=1;k<=n;k++)for(long p=0;p<x(n);p++){for(j=0,c=0;j<e.length;c=p%x(e[j])/x(e[j]-1)==p%x(e[j+1])/x(e[j+1]-1)?1:c,j+=2);if(c<1)return k;}return 0;}int x(int a){return(int)Math.pow(k,a);}

Il modo più ovvio per fare questo dato i vincoli è la forza bruta. Basta passare attraverso ciascun numero cromatico ke assegnare ciascun colore a ciascun vertice. Se nessun vicino ha lo stesso colore, hai il tuo numero. In caso contrario, spostati.

Questo richiede più tempo per il test case χ = 8(i grafici completi fanno schifo qui), ma è ancora meno di 15 secondi (ok, circa 100s con l'ultima modifica).

L'input è il numero di vertici ne una matrice di vertici di bordo e[]fornita nello stesso ordine dei valori separati da virgola degli OP.

Con interruzioni di riga:

int k,j,c;
int f(int n,int[]e){
    for(k=1;k<=n;k++)
        for(long p=0;p<x(n);p++){
            for(j=0,c=0;
                j<e.length;
                c=p%x(e[j])/x(e[j]-1)==p%x(e[j+1])/x(e[j+1]-1)?1:c,
                j+=2);
            if(c<1)return k;
        }
    return 0;
}
int x(int a){return(int)Math.pow(k,a);}

Oh, e questo presuppone che l'input sia una sorta di grafico colorabile. Se un bordo passa da v1 a v1 o non ci sono vertici, non può essere colorato e produrrà 0. Funzionerà comunque per grafici senza bordi χ=1, ecc.


2

Python 3 - 162

Utilizza lo stesso approccio a forza bruta, ma utilizza la libreria itertools per una generazione di combinazioni sperabilmente più veloce. Risolve l'8 grafico completo in <1 minuto sulla mia macchina abbastanza ordinaria.

import itertools as I
def c(n,v):
 for i in range(1,n+1):
  for p in I.product(range(i),repeat=n):
   if(0==len([x for x in v if(p[x[0]]==p[x[1]])])):return i

Esempio di utilizzo per il caso completo di 8 grafici:

print(c(8,[x for x in I.combinations(range(8), 2)]))

1

Haskell, 163 byte

p x=f(length x)(transpose x)1
f a[b,c]d|or$map(\x->and$g x(h b)(h c))(sequence$replicate a[1..d])=d|0<1=f a b c(d+1)
g a=zipWith(\x y->a!!x/=a!!y)
h=map(flip(-)1)

L'utilizzo sarebbe così:

p [[1, 2],[2, 3],[3, 1]]

Approccio di base alla forza bruta. Controlla tutte le possibili combinazioni di coloranti se sono valide. Non c'è molto altro da dire qui, tranne che sono felice di sentire qualche consiglio per accorciarlo ulteriormente;)


Direi che decrementare i vertici e trasporli conta come "preelaborazione". Quello che avevo in mente con "qualsiasi formato conveniente" era piuttosto che potevi scegliere da elenco semplice, elenco annidato, stringa, stringa con delimitatori convenienti, ecc ... ma la struttura appiattita dovrebbe essere la stessa specificata nella sfida.
Martin Ender,

@ MartinBüttner Va bene, lo cambierò
ThreeFx,

@ThreeFx all idè lo stesso di and, any idè lo stesso di ored any id$map f listè lo stesso di solo any f list. Inoltre, si potrebbe fare un paio di cose con g: è possibile ridefinire come g a=(and.).zipWith(\x y->a!!x/=a!!y), lo rendono infisso, modificare l'ordine di ingresso di sostituire (\x->g x b c)con g b co addirittura renderlo completamente punti-libero e inline esso. alcuni di questi non funzionano insieme, quindi
provali

1
@ MartinBüttner Penso che sia risolto, al costo di byte maaaaany. : D
ThreeFx,

1
Come risolvi il settimo esempio senza il numero di vertici nell'input?
Martin Ender,
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.