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
fonte
Respostas:
Python 2.7 -
122109111109108103Uso:
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.
fonte
all([...])
se incluir os parêntesesa,b
(que não custam caracteres aqui devido ao espaçamento) para queall
nã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, emm
vez de usar um loop while.any
e oand/or
truque, 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)
.Java -
241218A maneira mais óbvia de fazer isso, dadas as restrições, é a força bruta. Basta percorrer cada número cromático
k
e 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
n
e uma matriz de vértices de arestase[]
fornecida na mesma ordem que os valores separados por vírgula dos OPs.Com quebras de linha:
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.fonte
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.
Exemplo de uso para o caso completo de 8 gráficos:
fonte
Haskell, 163 bytes
O uso seria assim:
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;)
fonte
all id
é o mesmo queand
,any id
é o mesmoor
eany id$map f list
é o mesmo que apenasany f list
. Além disso, você pode fazer algumas coisas comg
: você pode redefini-la comog a=(and.).zipWith(\x y->a!!x/=a!!y)
, torná-lo infix, alterar a ordem de entrada para substituir(\x->g x b c)
comg b c
ou 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 :)