MO417 - Ata de exercícios

Grafos 1

Resolução dos Exercícios do dia 14/05/2003
Última alteração: 19/05/2003
Redator: Carlos R. Senna (022.248)

Nesta Ata estão as resoluções dos exercícios:

22.1-6 (pg. 422 [1])

22.2-6 (pg. 428 [1])

22.2-7 (pg. 428 [1])

22.1-6 Quando uma representação de matriz de adjacências é usada, a maioria dos algoritmos de grafos exige o tempo Ômega(V2 ) , mas existem algumas exceções. Mostre que detectar se um grafo orientado G contém um depósito universal – um vértice com grau de entrada |V| - 1 e grau de saída 0 – é uma operação que pode ser realizada no tempo O(V), dada uma matriz de adjacências para G.

Resolução: (apresentada pelo aluno Guilherme)

Um depósito universal (ou um sumidouro como foi chamado em aula), é um vértice onde todas as arestas chegam e nenhuma sai. A matriz de adjacências que representa um grafo que contém um sumidouro, terá a linha relativa a esse vértice totalmente preenchida com zeros e a coluna totalmente preenchida com uns, exceto na diagonal.

 

1

2

3

4

5

1

0

0

1

0

0

2

0

0

1

0

1

3

0

0

0

0

0

4

0

0

1

0

0

5

0

0

1

0

0

O algoritmo a seguir usa essa característica para encontrar o sumidouro.

SUMIDOURO(M, n)

2 // Procura por um candidato a sumidouro
1 i <- 1
3 for j <- 1 to n do
4    if M(i, j) = 1 then
5        i <- j  // candidato i falhou, tenta novo candidato j
6 // Verifica a coluna do candidato (diagonal = 0 resto = 1)
7 for k <- 1 to n do
8    if M(k, i) = 0 and k <> j then
9        return 0;   // Não achou sumidouro
10 // Verifica a linha do candidato (totalmente preenchida com zeros)
11 for a <- 1 to n do
12    if M(i, a) = 1 then
13        return 0;   // Não achou sumidouro
14 return i;    // Posição do sumidouro

 (Início)

22.2-6 Existem dois tipos de lutadores: "bons sujeitos" e "maus sujeitos". Entre qualquer par de lutadores profissionais pode ou não haver uma rivalidade. Suponha que temos n lutadores profissionais e temos uma lista de r pares de lutadores para os quais existem rivalidades. Dê um algoritmo de tempo O(n + r) que determine se é possível designar alguns dos lutadores como bons sujeitos e os restantes como maus sujeitos, de tal forma que a rivalidade ocorra em cada caso entre um bom sujeito e um mau sujeito. Se for possível realizar tal designação, seu algoritmo devia produzi-la.

Resolução: (apresentada pelo aluno André)

A solução é baseada numa busca em largura num grafo onde cada profissional será um vértice, e a rivalidade uma aresta ligando os vértices. Ao longo da busca, os vértices são marcados com um estado (e[v]) que pode ser BOM ou MAU, sendo que cada vértice novo recebe o estado contrário ao de seu pai na árvore produzida pela busca. A origem da busca será "um bom sujeito". Caso uma aresta de retorno leve a um vértice do mesmo estado, não se pode fazer a atribuição.

BOMMAU( G )

1 for cada vértice u pertencente V[G] do
2    cor[u] <- BRANCO
3    e[u] <- NIL
4 
5 for cada vértice s pertencente V[G] do
6    if cor[s] = BRANCO then 
7        cor[s] <- CINZA
8        e[s] <- BOM
9        Q <- vazio
10       ENQUEUE(Q, s)
11       while Q <> vazio do
12             u <- DEQUEUE(Q)
13             if e[u] = BOM then
14                estado <- MAU
15             else estado <- BOM
16             for cada v <- Adj[u] do
17                if cor[v] = BRANCO then
18                   cor[v] <- CINZA
19                   e[v] <- ESTADO
20                   ENQUEUE(Q, v)
21                else if e[u] = e[v] then
22                   return FALSE
23             cor[u] <- PRETO
24 return TRUE

 (Início)

22.2-7 O diâmetro de uma árvore T = (V, E) é dado por

             max sigma(u, v);    (onde sigma é a distância do caminho mais curto desde de u até v)
           u,v e V

isto é, o diâmetro é a maior de todas as distâncias de caminhos mais curtos na árvore. Forneça um algoritmo eficiente para calcular o diâmetro de uma árvore e analise o tempo de execução de seu algoritmo.

Resolução: (apresentada pelo aluno Bruno)

 A solução proposta é usar o algoritmo BFS (pag. 423 [1]), a partir de qualquer vértice para encontrar o último vértice, e executar novamente BFS a partir desse vértice para encontrarmos o diâmetro da árvore.

Diâmetro = dBFS(G, dBFS(G,s)) usando a versão modificada abaixo.

dBFS(G, s)
1 for cada vértice u pertencente a V[G] - {s}
2    do cor[u] <- BRANCO
3        d[u] <- infinito
4        pi[u] <- NIL
5 cor[s] <- CINZA
6 d[s] <- 0
7 pi[s] <- NIL
8 Q <- vazio
9 ENQUEUE(Q, s)
10 while Q <> vazio
11     do u <- DEQUEUE(Q)
12        for cada v <- Adj[u]
13           do if cor[v] = BRANCO
14                 then cor[v] <- CINZA
15                     d[v] <- d[u] + 1
16                     pi[v] <- u
17                     ENQUEUE(Q, v)
18        cor[u] <- PRETO
19 return u;

Ficou pendente a prova sobre essa solução proposta. Uma solução parcial de Ricardo e Daniele segue.

Suponha, sem perda de generalidade, que o diâmetro da árvore seja a distância entre os nós u e v. Então, há 2 casos possíveis de ocorrer na escolha do nó inicial para se executar a 1ª BFS: 1º) esse nó escolhido estar nesse caminho entre u e v; 2º) esse nó escolhido não estar nesse caminho entre u e v;

No 1º caso: Seja s esse nó pertencente ao caminho u e v. Então ao rodar a BFS com raiz em s termos que o nó mais distante de s encontrado pela execução do alg. BFS será, ou o nó u, ou o nó v (já que eles são as extremidades de um caminho mais longo). Suponha que o nó v tenha sido o nó mais distante encontrado (ou seja, o caminho de s para v é maior ou igual ao caminho de s para u. Nota: o contrário também poderia ocorrer sem perda de generalidade). Logo, ao rodar uma segunda vez o BFS, agora considerando como raiz o nó v, será encontrado o caminho mais longo (caminho de v para u).

Prova: suponha que existisse um caminho mais longo de s para v (por exemplo, até um nó v'), então esse caminho seria o escolhido durante a execução da primeira BFS. Logo, estou dizendo que existe um caminho de s até v' que é maior do que o caminho de s até v. Logo, o caminho mais longo existente na árvore seria um caminho de u até v' o que contradizeria a minha hipótese de que um caminho mais longo é aquele entre os nós u e v ! Consequentemente, se eu der a sorte de selecionar um nó pertencente ao caminho mais longo, obrigatoriamente, na segunda vez que executar o BFS estarei executando-o sobre uma das folhas de um caminho mais longo da árvore !

No 2º caso: Seja s' um nó não pertencente ao caminho mais longo da árvore (caminho de u até v). Rodando o alg. de BFS com raiz em s' teremos a seguinte situação: um caminho de s' até s (um nó pertencente ao caminho mais longo) mais um caminho de s até u ou v. Consequentemente, a segunda execução da BFS iniciará em um nó folha pertencente ao caminho mais longo e encontrará o caminho mais longo da árvore.

Prova: Basta provar que um caminho com raiz em s CRUZARÁ o caminho mais longo (caminho u até v), pois a partir desse ponto (nó s) o caminho escolhido pela BFS será o mesmo do apresentado no 1º caso. Isso é verdade por definição no alg. BFS, já que em algum ponto o alg. de BFS com raiz em s' atingirá o nó s !

 (Início)

[1] Livro Texto adotado: Cormen, T.H.;Leiserson, C.E.; Rivest, R.L.; Stein, C.; Algoritmos: teoria e prática. Tradução da 2ª edição americana Teoria e Prática. 2002.