Encontre o número cromático

13

Surpreendentemente, ainda não tivemos nenhum desafio na coloração de gráficos!

Dado um gráfico não direcionado, podemos atribuir a cada vértice uma cor de modo que não dois vértices adjacentes compartilhem a mesma cor. O menor número χ de cores distintas necessárias para conseguir isso é chamado número cromático do gráfico.

Por exemplo, o seguinte mostra uma coloração válida usando o número mínimo de cores:

(Encontrado na Wikipedia)

Portanto, o número cromático deste gráfico é χ = 3 .

Escreva um programa ou função que, dado um número de vértices N <16 (numerados de 1 a N ) e uma lista de arestas, determine o número cromático de um gráfico.

Você pode receber a entrada e produzir a saída em qualquer formato conveniente, desde que a entrada não seja pré-processada. Ou seja, você pode usar uma string ou uma matriz, adicionar delimitadores convenientes à string ou usar uma matriz aninhada, mas faça o que fizer, a estrutura nivelada deve conter os mesmos números que os exemplos abaixo (na mesma ordem).

Você não pode usar funções internas relacionadas à teoria dos grafos (como as do Mathematica ChromaticNumber).

Você pode assumir que o gráfico não possui loop (uma aresta conectando um vértice a ele mesmo), pois isso tornaria o gráfico incolor.

Isso é código de golfe, a resposta mais curta (em bytes) vence.

Exemplos

Seu programa deve pelo menos resolver todos eles em um período de tempo razoável. (Ele deve resolver todas as entradas corretamente, mas pode levar mais tempo para entradas maiores.)

Para encurtar a postagem, nos exemplos a seguir, apresento as bordas em uma única lista separada por vírgula. Em vez disso, você pode usar quebras de linha ou esperar a entrada em algum formato de matriz conveniente, se preferir.

Triângulo (χ = 3)

3
1 2, 2 3, 1 3

"Anel" de 6 vértices (χ = 2)

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

"Anel" de 5 vértices (χ = 3)

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

Exemplo de imagem acima (χ = 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

Generalização do exposto para 7 vértices (χ = 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

Gráfico de 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

Gráfico completo de 5 vértices, mais vértice desconectado (χ = 5)

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

Gráfico completo de 8 vértices (χ = 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

Estrutura triangular com 15 vértices (χ = 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
Martin Ender
fonte
Você poderia definir razoável? 1 minuto? 10?
ThreeFx
@ThreeFx sim, 10 minutos é razoável. meio dia não é. Não quero ser muito rigoroso no limite, porque preciso testar tudo novamente na mesma (minha) máquina. mas digamos que se estiver concluído dentro de uma hora na sua máquina, tudo bem.
Martin Ender

Respostas:

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)])

Força bruta aumentando o número cromático (m) e verifique todos os corantes possíveis. Uma coloração pode ser descrita como um número na base m. Portanto, as cores possíveis são 0, 1, ..., m ^ n-1.

editar: O gráfico completo de 8 vértices leva bastante tempo. Mas meu laptop resolve em 10 minutos. Os outros casos de teste levam apenas alguns segundos.


edit 2: Leia que o pré-processamento é permitido, então deixo o índice dos vértices começar com 0: reduz t * m // m ** x% m para t // m ** a% m (-2). Dissolver lambda e colocar m nos parâmetros de função (-11)


editar 3: pré-processamento não é permitido -> voltar para t * m (+4), simplificado // para / (-2).


edit 4: remova colchetes em qualquer (-2), obrigado xnor.


editar 5: em vez de tomar o módulo m duas vezes, basta subtraí-los e depois usar o módulo (-1). Isso também é uma melhoria de desempenho. Todos os casos de teste juntos levam cerca de 25 segundos no meu laptop.


edite 6: chamada recursiva em vez de enquanto 1: e m + = 1 (-5). Mais uma vez obrigado, xnor.

Jakube
fonte
Bom método. Um simples jogo de golfe: você pode remover os colchetes all([...])se incluir os parênteses a,b(que não custam caracteres aqui devido ao espaçamento) para que allnão os confunda com argumentos adicionais. Além disso, suspeito que você pode salvar caracteres se recuar com uma chamada de função para a próxima mais alta, em mvez de usar um loop while.
xnor
Obrigado, a abordagem recursiva leva +2 caracteres. Uma abordagem para m na faixa (n + 1) também.
Jakube 13/09
I otimizado a abordagem recursiva um pouco com anye o and/ortruque, e então ele salva alguns caracteres: 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);}

A maneira mais óbvia de fazer isso, dadas as restrições, é a força bruta. Basta percorrer cada número cromático ke atribuir cada cor a cada vértice. Se nenhum vizinho for da mesma cor, você terá seu número. Caso contrário, siga em frente.

Isso leva mais tempo para o caso de teste χ = 8(gráficos completos são ruins aqui), mas ainda é inferior a 15 segundos (ok, cerca de 100 segundos com a edição mais recente).

Entrada é o número de vértices ne uma matriz de vértices de arestas e[]fornecida na mesma ordem que os valores separados por vírgula dos OPs.

Com quebras de linha:

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);}

Ah, e isso pressupõe que a entrada seja algum tipo de gráfico colorido. Se uma aresta fizer um loop de v1 a v1, ou se não houver vértices, ela não poderá ser colorida e produzirá 0. Ele ainda funcionará para gráficos sem arestas χ=1, etc.

Geobits
fonte
2

Python 3-162

Usa a mesma abordagem de força bruta, mas usa a biblioteca itertools para uma geração de combinação esperançosamente mais rápida. Resolve os 8 gráficos completos em <1 minuto na minha máquina bastante comum.

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

Exemplo de uso para o caso completo de 8 gráficos:

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

Haskell, 163 bytes

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)

O uso seria assim:

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

Abordagem básica da força bruta. Verifique todas as combinações de cores possíveis, se forem válidas. Não há muito mais a dizer aqui, exceto que estou feliz em ouvir algumas dicas para diminuir ainda mais isso;)

ThreeFx
fonte
Eu diria que decrementar os vértices e transpor eles conta como "pré-processamento". O que eu tinha em mente com "qualquer formato conveniente" era preferir escolher entre lista simples, lista aninhada, sequência, sequência com delimitadores convenientes, etc ... mas a estrutura nivelada deve ser a mesma especificada no desafio.
Martin Ender
@ MartinBüttner Tudo bem, eu vou mudar isso
ThreeFx
@ThreeFx all idé o mesmo que and, any idé o mesmo ore any id$map f listé o mesmo que apenas any f list. Além disso, você pode fazer algumas coisas com g: você pode redefini-la como g a=(and.).zipWith(\x y->a!!x/=a!!y), torná-lo infix, alterar a ordem de entrada para substituir (\x->g x b c)com g b cou mesmo torná-lo completamente pontos-livre e inline. algumas delas não funcionam em conjunto, de modo a tentar todos eles e escolher o melhor :)
haskeller orgulhoso
1
@ MartinBüttner Eu acho que é fixo, ao custo de muitos bytes. : D
ThreeFx
1
Como você está resolvendo o 7º exemplo sem o número de vértices na entrada?
Martin Ender