Algoritmos para Grafos | Índice
Este capítulo apresenta o importante problema da coloração dos vértices de grafos não-dirigidos. Como não se conhecem bons algoritmos para o problema, vamos nos limitar a examinar algumas heurísticas simples.
Sumário:
Uma coloração dos vértices de um grafo não-dirigido é uma atribuição de cores aos vértices tal que cada vértice recebe uma e uma só cor. Portanto, uma coloração nada mais é que uma numeração dos vértices. Podemos dizer também que uma coloração é uma partição do conjunto de vértices: cada bloco da partição corresponde a uma cor.
Uma coloração de um grafo é válida se
as duas pontas de cada aresta têm cores diferentes.
(Quando o contexto permite, dizemos coloração de um grafo
,
deixando a expressão dos vértices
subentendida.)
A figura ao lado mostra um grafo não-dirigido e
uma coloração válida com 3 cores.
Uma bicoloração
é uma coloração válida com 2 cores.
A expressão coloração com k cores
não significa que todas as k cores são usadas;
significa apenas que o número de cores não passa de k.
Portanto, uma coloração válida com k cores
também é uma coloração válida com k +1 cores.
A propósito, dizemos que um grafo é k-colorível
se tem uma coloração válida com k cores.
Encontrar colorações válidas com muitas cores (tantas quantas são os vértices, por exemplo) é fácil. Encontrar colorações válidas com poucas cores é bem mais difícil.
Problema da coloração mínima de vértices: Dado um grafo não-dirigido G, encontrar uma coloração válida de G com o menor número de cores possível.
Vale a pena mencionar a seguinte variante do problema: dado um grafo não-dirigido G e um inteiro k, encontrar uma coloração válida de G com k cores. (É claro que nem toda instância dessa variante tem solução.) Essa variante é computacionalmente equivalente ao problema da coloração mínima, embora isso não seja imediatamente aparente.
É fácil provar que um grafo é k-colorível: basta exibir uma coloração válida com k cores. Mas como provar que um dado grafo não é k-colorível? Essa questão está na base da dificuldade do problema da coloração.
Exemplo A. Uma indústria química precisa armazenar os reagentes que tem em estoque. Por razões de segurança, alguns pares de reagentes não podem ficar no mesmo galpão. Qual o número mínimo de galpões necessário para armazenar todos os reagentes? Nesse exemplo, cada reagente é um vértice do grafo, reagentes incompatíveis definem as arestas, e cada galpão é uma cor.
Exemplo B. O quebra-cabeça Sudoku consiste em preencher uma matriz 9-por-9 com os números 1 2 3 ... 9 de tal forma que cada linha seja uma permutação de 1..9, cada coluna seja uma permutação de 1..9 e cada uma das nove submatrizes 3-por-3 com borda mais escura seja uma permutação de 1..9. Esse quebra-cabeça é uma instância do problema da coloração mínima. Os vértices do grafo são as 81 casas da matriz e dois vértices são vizinhos se estiverem na mesma linha, ou na mesma coluna, ou na mesma submatriz 3-por-3 com borda escura. O desafio está em obter uma coloração válida com as cores 1 2 3 ... 9. Para tornar o Sudoku mais interessante, a matriz é apresentada com uma coloração incompleta (números pretos na figura) e o desafio é completar essa coloração incompleta (números vermelhos na figura).
Para encontrar uma coloração válida de um grafo
com k de cores
poderíamos simplesmente fazer uma lista
de todas as colorações
com k cores
e eliminar, sistematicamente, as que não são válidas.
Mas esse algoritmo força bruta
é extremamente lento,
pois o número de colorações
cresce exponencialmente com o número de vértices do grafo.
Um algoritmo rápido para o problema da coloração mínima ainda não foi descoberto. Suspeita-se mesmo que um tal algoritmo não existe. Em vista disso, trataremos neste capítulo apenas de algumas heurísticas simples. Essas heurísticas produzem colorações válidas mas em geral usam mais cores que o mínimo necessário.
A seguinte heurística, conhecida como algoritmo de coloração sequencial, produz uma coloração válida de qualquer grafo. No início de cada iteração, temos uma coloração válida incompleta que usa as cores 0 1 2 ... k−1. Cada iteração consiste no seguinte:
Em geral, cada iteração tem vários candidatos para o papel de c, ou seja, tem mais de uma cor disponível para o vértice v. O algoritmo escolhe qualquer uma das cores disponíveis, sem medir as consequências que essa escolha terá em iterações futuras (note que o algoritmo não pode se arrepender e mudar uma escolha feita no passado). Esse comportamento é conhecido como guloso (= greedy).
Veja uma implementação do algoritmo guloso de coloração sequencial:
#define UGraph Graph
/* Esta função calcula uma coloração válida dos vértices do grafo não-dirigido G e devolve o número de cores usadas. A coloração é armazenada no vetor color[]. */
int UGRAPHseqColoring( UGraph G, int *color) { int k = 0; for (vertex v = 0; v < G->V; ++v) color[v] = -1; for (vertex v = 0; v < G->V; ++v) { // as cores são 0..k-1 bool available[100]; int c; for (c = 0; c < k; ++c) available[c] = true; for (link a = G->adj[v]; a != NULL; a = a->next) { if (color[a->w] != -1) available[color[a->w]] = false; } // A c = 0; while (c < k && !available[c]) ++c; if (c < k) color[v] = c; else color[v] = k++; } return k; }
No início de cada iteração, o conjunto de cores é 0..k-1. No ponto A, available[0..k-1] é o vetor característico do conjunto de cores disponíveis para o vértice v.
É claro que a coloração produzida pelo algoritmo é válida. Mas o número de cores pode ser bem maior que o mínimo necessário. Assim, do ponto de vista do problema da coloração mínima, esse algoritmo guloso é apenas uma heurística.
Exemplo C. Considere o grafo com conjunto de arestas 0-3 3-5 5-1 1-6 6-4 4-2. Aplique a função UGRAPHseqColoring() a esse grafo. Veja o estado do vetor color[] no início de cada iteração:
v 0 1 2 3 4 5 6 color - - - - - - - 0 - - - - - - 0 0 - - - - - 0 0 0 - - - - 0 0 0 1 - - - 0 0 0 1 1 - - 0 0 0 1 1 2 - 0 0 0 1 1 2 2
A função usa 3 cores, mas o grafo é bicolorível.
Para fugir do caráter guloso do algoritmo de coloração sequencial, podemos permitir que o algoritmo reveja decisões tomadas em iterações anteriores.
Suponha dada uma coloração válida incompleta
do grafo não-dirigido G e um vértice v
que ainda não foi colorido.
Suponha que dispomos de k cores apenas
e que cada uma das cores é usada
na vizinhança de v.
É possível alterar a coloração corrente
de modo que alguma das cores saia da vizinhança de v
e assim fique disponível para v?
Eis uma
heurística da troca de cores em componentes bicoloridas
que pode fazer isso.
Suponha, para simplificar, que a cor 0 aparece uma só vez na vizinhança de v. Digamos que w é o vizinho de v que tem cor 0. Seja X o conjunto dos vértices que têm cor 0 ou 1 e considere o subgrafo não-dirigido G[X] induzido por X. (Veja o exercício Componentes de subgrafos induzidos no capítulo Componentes conexas.) Suponha que a componente conexa de G[X] que contém w não contém nenhum dos vizinhos de v que têm cor 1. Nesse caso, se intercambiarmos as cores 0 e 1 em X, a cor 0 ficará disponível para v!
Essa heurística pode, às vezes, reduzir o número de cores usado pelo algoritmo de coloração sequencial. (Em geral, entretanto, a heurística não produz uma coloração válida com número mínimo de cores.)
Exemplo D. Considere a coloração válida incompleta do grafo grade da figura. Os números 0 1 2 indicam as cores. Digamos que o vértice v não tem cor. Como esse vértice tem vizinhos de cores 0, 1 e 2, não pode receber nenhuma dessas cores.
0 -- 2 -- 1 -- 2 -- 0 | | | | | 2 -- 1 -- 2 -- 0 -- 1 x | | | | | | 1 -- 0 -- -- 1 -- 2 w -- v -- y | | | | | | 0 -- 1 -- 2 -- 0 -- 1 z
Os vizinhos de v, em sentido horário a partir do oeste, são w x y z. A componente das cores 0 e 1 que contém w não contém y. Portanto, se intercambiarmos as cores 0 e 1 na componente que contém w, a cor 0 ficará disponível para v. (Tente repetir esse truque com outros pares de cores e outros vizinhos de v.)
Uma clique num grafo não-dirigido é um conjunto de vértices adjacentes entre si. A figura mostra uma clique de tamanho 4. Encontre cliques de tamanho 5, 6 e 7 na figura.
É fácil encontrar uma clique pequena num grafo não-dirigido: cada vértice é uma clique de tamanho 1 e cada aresta corresponde a uma clique de tamanho 2. É bem mais difícil encontrar uma clique grande.
Problema da clique máxima: Encontrar uma clique de tamanho máximo num grafo não-dirigido.
Há uma relação simples entre cliques e coloração de vértices: se um grafo não-dirigido tem uma clique de tamanho q, então qualquer coloração válida precisa de pelo menos q cores. Portanto, se um grafo não-dirigido tem uma clique de tamanho q e uma coloração válida com apenas q cores, a coloração é mínima e a clique é máxima. (Em geral, entretanto, uma clique máxima é bem menor que o número de cores de uma coloração válida mínima.)
Exemplo E. No grafo do Sudoku (veja o exemplo B), há cliques com 9 vértices e portanto toda coloração válida precisa de pelo menos 9 cores. Por outro lado, qualquer coloração que use apenas 9 cores prova que o grafo não tem cliques com mais que 9 vértices.
Resposta:
Eu gostaria de fazer isso,
mas ao discutir algumas heurísticas
sou levado a examinar colorações provisórias inválidas
,
que atribuem a mesma cor a dois vértices adjacentes.
Resposta: Não. Por definição, um grafo é k-cromático se for k-colorível mas não (k−1)-colorível.