Listas de exercícios

Exercícios durante as aulas.

Exercícios da aula 3

Directed_acyclic_graph.png

E03.1  Exiba uma numeração topológica do digrafo da figura. A numeração não precisa ser injetiva.

E03.2  Verifique se o digrafo cujos arcos são  0-1 1-2 2-3 4-5 5-6 6-7 8-9 9-10 9-11  é uma floresta radicada.  Em caso afirmativo, dê uma numeração topológica dos vértices.

E03.3  Exiba um digrafo que tem pelo menos uma fonte, não tem vértices com grau de entrada maior que 1, mas não é uma floresta radicada.

E03.4  Escreva uma função que diga se um dado digrafo é bipartido. Em caso afirmativo, a função deve devolver uma numeração topológica que só tem dois valores. Que informação o algoritmo deve devolver para comprovar uma resposta negativa?

Exercícios da aula 4

E04.1  Qual o resultado de DIGRAPHdfs() quando G->A vale 0?  E quando G->V vale 1?

figs/mine/diwheel6-j20.png

E04.2  Faça uma busca DFS no exemplo da figura percorrendo cada linha da matriz de adjacências ao contrário, isto é, de V-1 para 0. Escreva o rastreamento.

mine/rtree10c.png

E04.3  É possível representar o digrafo ao lado por listas de adjacência de modo que a ordenamento dos vértices em pré-ordem seja  0 4 3 1 2 6 9 7 8 5?  Se sua resposta for afirmativa, dê as listas de adjacência. Se for negativa, explique por quê.  Repita o exercício com  0 3 1 2 4 5 6 7 9 8?

E04.4  Em geral, a ordem em que os vértices são examinados para determinar o início de uma nova etapa da busca DFS — linha for (v = 0; v < G->V; v++) de DIGRAPHdfs — não é importante.  Entretanto, em certos algoritmos (como o das componentes fortes), é necessário examinar os vértices numa determinada ordem.  Escreva uma variante de DIGRAPHdfs que examine os vértices na ordem dada por um ordenamento ord[0..V-1] dos vértices (o vetor ord[] é um dos argumentos da função).

Exercícios da aula 5

undirected graph with 8 vertices

E05.1  Considere o grafo definido pelas arestas  0-2 2-6 6-4 4-5 5-0 0-7 7-1 7-4 3-4 3-5.  Suponha que o grafo é representado por uma matriz de adjacências. Submeta o grafo à função DIGRAPHdfs() e faça o rastreamento da execução da função e a correspondente classificação dos arcos.
Dê o estado final dos vetores pre[], pos[]pai[].  Depois, dê o correspondente ordenamento dos vértices em pós-ordem.

E05.2  Considere o digrafo definido pelos arcos  0-1 1-2 2-3 3-4 2-4 4-2.  Diga qual o tipo — retorno, descendente, ou cruzado — de cada arco.

E05.3  Dê um exemplo de um digrafo e um arco v-w com a seguinte propriedade: depois de uma execução da função DIGRAPHdfs() tem-se pre[v] < pre[w] e pos[v] < pos[w].

E05.4  Escreva uma função que receba os vetores pre[] e pai[] produzidos por DIGRAPHdfs() e imprima o tipo (floresta, de retorno, descendente, ou cruzado) de cada arco. (Dica: basta verificar se uma ponta do arco é ancestral ou descendente de outra.)  Qual o consumo de tempo de sua função?

Exercícios da aula 6

E06.1  Suponha dada uma função booleana DIGRAPHreach() que decide se existe um caminho de um dado vértice v a um dado vértice w em um digrafo G. Use essa função para escrever uma função que decida se um digrafo tem um ciclo. Estime o consumo de tempo de sua função.

E06.2  Encontre um ciclo num digrafo sem sorvedouros. Quanto tempo o seu algoritmo consome?

Directed_acyclic_graph.png

E06.3  Escreva uma função que decida se um digrafo é acíclico com base na seguinte ideia:  recursivamente, remova fontes do digrafo; a ordem em que os vértices são removidos dá um ordenamento topológico se todos os vértices forem removidos; senão, o grafo que sobrar não tem fontes e portanto não é acíclico.  Quanto tempo o seu algoritmo consome?

E06.4  Considere o algoritmo de detecção de ciclo que usa as numerações em pré-ordem e pós-ordem. Aplique o algoritmo ao digrafo definido pelas listas de adjacência abaixo. Repita o exercício depois de inverter a direção do arco 5-6.

     0: 1
     1: 2
     2: 3
     3: 5 6 4
     4: 2
     5: 6
     6: 1

Exercícios da aula 7

E07.1  Aplique o algoritmo de detecção de ciclo ao digrafo definido pelas listas de adjacência abaixo à esquerda. Repita o exercício para o digrafo definido pelas listas de adjacência abaixo à direita. (Aproveite para dar a classificação dos arcos.)

     0: 1                 0: 1
     1: 2                 1: 2
     2: 3                 2: 3
     3: 5 6 4             3: 5 6 4
     4: 2                 4: 2
     5: 6                 5: 
     6: 1                 6: 5 1

E07.2  Quantos arcos, no máximo, pode ter um DAG com V vértices?

E07.3  É verdade que cada arco de um digrafo fortemente conexo pertence a um ciclo?

E07.4  É verdade que cada etapa da busca DFS em um digrafo visita os vértices de uma e uma só componente forte?

E07.5  Em que condições um DAG é fortemente conexo?

E07.6  Que cara têm as componentes fortes de um DAG?

Exercícios da aula 8

E08.1  Escreva uma função que decida se um digrafo é fortemente conexo em tempo proporcional a V + A, sendo V o número de vértices e A o número de arcos do digrafo.  (Sugestão: faça uma busca no digrafo inverso.)

E08.2  Suponha que um DAG é submetido a uma busca em profundidade. Como o primeiro vértice de cada etapa deve ser escolhido de modo cada árvore da floresta DFS resultante tenha um só vértice?

E08.3  Mostre que uma busca em profundidade em um digrafo fortemente conexo tem uma só etapa (qualquer que seja o vértice inicial da busca).  A recíproca é verdadeira?

Directed_acyclic_graph.png

E08.4  Aplique o algoritmo de Kosaraju-Sharir ao digrafo da figura.

Exercícios da aula 9

E09.1  Mostre que todos os vértices de qualquer ciclo de um digrafo pertencem à mesma componente forte.

digrafo com 4 componentes fortes

E09.2  Identifique a olho as componentes fortes do digrafo e faça um desenho do digrafo das componentes fortes.

E09.3  Escreva um algoritmo simples (mesmo que não seja eficiente) que calcule as componentes fortes de um digrafo G. O algoritmo deve devolver o número de componentes fortes do digrafo e preencher um vetor sc[] indexado pelo vértices tal que sc[v] == sc[w] se e somente se vw pertencem à mesma componente forte.  (Sugestão: use a função DIGRAPHreach().)  Quanto tempo o seu algoritmo consome?

E09.4  Suponha que as componentes fortes de um digrafo G são numerados de 0k-1.  Seja sc[] uma numeração dos vértices de G que associa a cada vértice o número da componente forte a que o vértice pertence.  Escreva uma função que receba G e sc[] e construa o digrafo das componentes fortes de G.

Directed_acyclic_graph.png

E09.5  Aplique o algoritmo de Kosaraju-Sharir ao digrafo da figura.

Sedgewick-Wayne/strong-comps-G.png

E09.6  Aplique o algoritmo de Kosaraju-Sharir ao digrafo da figura. Na primeira fase do algoritmo, tome os vértices em ordem decrescente de nomes. %

E09.7  O algoritmo de Kosaraju-Sharir calcula um ordenamento em pós-ordem, digamos L1, dos vértices do digrafo inverso e depois processa o digrafo original na ordem inversa de L1.  Não seria mais simples evitar essas duas inversões e fazer o seguinte:  calcular o ordenamento em pós-ordem, digamos L0, dos vértices do digrafo original e depois processar o digrafo original na ordem L0?  (Sugestão: Considere o digrafo definido pelos arcos  0-1 1-2 2-3 3-1 2-4 3-5 , que consiste em um ciclo com três pernas.)

Exercícios da aula 10

E10.1  Aplique o algoritmo de Kosaraju-Sharir (função DIGRAPHscKS()) ao digrafo G da primeira figura abaixo.  (A segunda figura mostra o digrafo inverso GR.) Tome os vértices em ordem decrescente de nomes.

Sedgewick-Wayne/strong-comps-G.png                     Sedgewick-Wayne/strong-comps-reverse-G.png

figs/mine/rtree10c.png

E10.2  Faça um rastreamento da busca em largura, a partir do vértice 5, na árvore radicada da figura. Observe que a busca em largura percorre a árvore por níveis.

E10.3  Depois de executar a função DIGRAPHbfs() com argumentos Gs, seja  X  o conjunto dos vértices v para os quais num[v] é diferente de -1.  Descreva o leque de X.

E10.4  Considere uma busca em largura num grafo a partir de um vértice s.  Seja v-w um arco do grafo e suponha que w não é filho de v nem pai de v na árvore de busca em largura.  Mostre que v não é ancestral nem descendente de w.

Exercícios da aula 11

E11.1  Seja s um vértice de um digrafo G. Suponha que conhecemos a distância de s a cada um dos demais vértices de G. O que se pode dizer sobre a distância entre dois vértices quaisquer vw?   Repita o exercício com grafo no lugar de digrafo.

E11.2  Mostre que no início de cada iteração de DIGRAPHdist() existe um inteiro positivo d tal que a sequência de valores de dist[] ao longo da fila é  d d ... d  ou  d d ... d d+1 ... d+1.  (Não é possível, por exemplo, que a sequência seja  d d d d+1 d+1 d d.)

E11.3  A função DIGRAPHbfs() (e também a função DIGRAPHdist()) constrói uma árvore BFS no digrafo. Essa árvore satisfaz a definição de árvore radicada?

E11.4  Um digrafo G é submetido a dois algoritmos de componentes fortes. Cada algoritmo produz uma numeração dos vértices que identifica a componente forte a que cada vértice pertence. O primeiro produz uma numeração sc1[] e o segundo produz uma numeração sc2[]. Se os algoritmos forem corretos, sc1[] e sc2[] devem ser equivalentes. Escreva um algoritmo que decida se sc1[] e sc2[] são equivalentes.

E11.5  Escreva uma função que decida se um digrafo G é uma árvore radicada. Em caso afirmativo, a função deve depositar no vetor pre[] uma numeração topológica de G.  (Sugestão: Faça uma busca em profundidade e veja a classificação dos arcos.)

E11.6  Generalize o código de DIGRAPHdist() para calcular caminhos mínimos a partir de um conjunto:  dado um conjunto não vazio S de vértices, determinar, para cada vértice t, um caminho mínimo dentre os que começam em S e terminam em t.

Exercícios da aula 12

E12.1  Considere o grafo cujas arestas são  0-1 0-2 0-3 1-2 1-3 2-3 .  Faça uma lista de todos os ciclos não triviais do grafo que não sejam equivalentes entre si.

E12.2  Aplique a função GRAPHhasCircuit() ao grafo cujas arestas são  0-1 0-2 0-3 1-2 1-3 2-3 .

E12.3  A função GRAPHhasCircuit() é capaz de encontrar um circuito em um digrafo não simétrico?

E12.4  Escreva uma função que decida se um dado grafo tem um circuito fazendo uma busca em largura.  Use a função que calcula distâncias como inspiração (mas lembre-se de que sua função só se aplica a grafos).  Para simplificar, você pode supor que o grafo é conexo.

E12.5  Escreva uma função que construa uma árvore aleatória com V vértices.

E12.6  Mostre que toda árvore com V vértices tem exatamente V − 1 arestas.  Mostre que toda floresta com V vértices e C componentes conexas tem exatamente V − C arestas.

E12.7  Prove que toda floresta com pelo menos uma aresta tem pelo menos duas folhas.

Exercícios da aula 13

younger1-thick.png

E13.1a  O grafo da figura admite bipartição?  (Aqui, admite é o mesmo que tem.)

younger2-thick.png

E13.1b  O grafo da figura admite bipartição?  (Aqui, admite é o mesmo que tem.)

E13.2  Mostre que toda floresta é bicromática.

E13.3  Suponha que um grafo tem um ciclo ímpar.  Mostre que o grafo não admite bipartição.

E13.4  Acrescente código a GRAPHtwocolor() para construir uma floresta DFS durante a busca.  Em seguida, mostre que as cores dos vértices são alternadamente 0 e 1 ao longo de qualquer caminho na floresta DFS.

E13.5  Escreva uma função que use busca em largura para reconhecer grafos bipartidos.  (Sugestão: comece por calcular a distâncias de um vértice s a cada um dos outros; para toda aresta v-w, as distâncias de sv e de sw devem ter paridade diferente, ou seja, uma deve ser par e a outra deve ser ímpar.)

E13.6  [Difícil] Escreva uma função que procure um circuito de comprimento par num grafo.  (Sugestão: calcule todas as distâncias a partir de algum vértice s e estude cuidadosamente a árvore das distâncias.)

Exercícios da aula 14

E14.1  Seja subset[] um vetor de 0s e 1s indexado pelos vértices de um grafo G. Seja X o conjunto de vértices indicado pelos 1s do vetor subset[]. Escreva uma função que calcule as componentes conexas do subgrafo induzido por X.

E14.2  Generalize o código de DIGRAPHdist() para calcular caminhos mínimos a partir de um conjunto:  dado um conjunto não vazio S de vértices, determinar, para cada vértice t, um caminho mínimo dentre os que começam em S e terminam em t.

E14.3  [Relação entre bipartição e distância.]  Seja s um vértice qualquer de um grafo conexo G.  Para cada vértice x, denote por d(x) a distância de sx.  Suponha que  d(v) ≠ d(w)  para cada aresta v-w.  Prove que G é bipartido.  (Dica: exiba uma bicoloração do vértices.)

E14.4  Escreva uma função que receba um grafo e encontre uma bicoloração dos vértices ou um ciclo ímpar. Sua função deve usar busca em largura. A bicoloração (se existir) deve ser armazenada num vetor color[]. O ciclo ímpar (se existir) deve ser armazenado num vetor circuit[].  (Dica: O grafo pode ser desconexo. Em cada componente conexa, tome um vértice s e faça uma BFS a partir de s, como estivesse calculando distâncias a partir de s.)  Não use vetores dist[] nem num[]; basta usar color[]pai[].

E14.5  Escreva uma função que construa uma árvore aleatória com V vértices.

E14.6  [Coloração de vértices.]  Seja G o seguinte grafo: comece com grade simétrica m-por-n; depois, acrescente diagonais noroeste-sudeste a todos os pequenos quadrados.  Mostre que G admite uma coloração válida dos vértices com 3 cores apenas.

queen8x8.png

E14.7  [Coloração de vértices.]  Qual o número mínimo de cores necessário para uma coloração válida do grafo da dama do jogo de xadrez?  Trate de tabuleiros 2-por-2, depois de tabuleiros 3-por-3, etc.

Exercícios da aula 15

E15.1  A primeira iteração de GRAPHsequentialColoring() está correta?  A função produz uma coloração válida quando o grafo tem apenas um ou dois vértices?  Ela produz uma coloração válida quando o grafo não tem arestas?

E15.2  Quantas cores a função GRAPHsequentialColoring() usa para colorir um grafo bipartido?

E15.3  Aplique GRAPHsequentialColoring() à grade simétrica 4×5 com diagonais.

E15.4  Quantas cores, no máximo, GRAPHsequentialColoring() usa?  (Dê uma resposta em função de algum parâmetro do grafo.)  Como escolher um bom valor para o tamanho maxk do vetor disponivel[]?

E15.5  Heurística de Brelaz.  Esta é uma variante do algoritmo de coloração sequencial. Suponha dada uma coloração parcial válida de um grafo G e suponha que o conjunto de cores é 0 1 2 ... k-1.  Em cada iteração, escolha um vértice incolor v que seja adjacente ao maior número de cores diferentes.  Aplique a v a menor cor que seja diferente das cores usadas nos vizinhos de v.  Implemente esse algoritmo.

E15.6  Implemente o algoritmo de coloração sequencial combinado com a heurística das componentes bicoloridas.

Exercícios da aula 16 (emparelhamentos)

figs/grafos-exercicios/3-2-bipartite-thick.png

E16.1  Encontre um emparelhamento máximo no grafo da figura.

figs/grafos-exercicios/grade-4-3-nolabels-thick.png

E16.2  Grade simétrica.  Encontre um emparelhamento máximo numa grade simétrica m-por-n.

figs/grafos-exercicios/cube-thick-matching.png       figs/grafos-exercicios/3-2-bipartite-thick-matching-3.png

E16.3  Encontre um caminho aumentador para o emparelhamento vermelho. Encontre dois caminhos alternantes que não sejam aumentadores.

E16.4  Escreva uma função que receba um grafo G e um vetor match[] de vértices indexado por vértices e verifique se o vetor representa um emparelhamento.  Segunda parte: imprima a lista de arestas do emparelhamento representado por match[].

Exercícios da aula 17 (emparelhamentos bipartidos)

figs/grafos-exercicios/bip-younger1-thick.png

E17.1  Calcule um emparelhamento máximo no grafo da figura.  Prove que o seu emparelhamento é máximo.

E17.2  Seja K uma cobertura e M um emparelhamento em um grafo.  Prove que  |K| ≥ |M|.

E17.3  É verdade que em qualquer grafo (bipartido ou não) existe uma cobertura K e um emparelhamento M tais que |K| = |M|?

E17.4  Mostre que, em qualquer grafo (bipartido ou não), o tamanho de um emparelhamento maximal é pelo menos 50% do tamanho de um emparelhamento máximo.

Exercícios da aula 18 (pontes)

E18.1  Considere o grafo definido pelo conjunto de arestas  0-1 1-2 2-0 1-3 1-4 4-5 5-6 6-4.  Para cada aresta, diga se ela é uma ponte ou se seus arcos pertencem a ciclos não-triviais.

E18.2  Considere o grafo definido pelas arestas  0-1 1-2 2-3 3-4 4-5 5-6 6-7 7-8 8-9 9-0.  Escolha uma floresta DFS em G e calcule o vetor low[].

E18.3  Mostre o rastro da aplicação do algoritmo GRAPHbridges() ao grafo definido pelas arestas  0-9 9-6 6-1 1-3 3-2 2-7 3-4 4-5 4-8 9-8 6-3 3-7.  Suponha que os vértices são sempre examinados em ordem crescente de nomes.

E18.4  Quantas componentes aresta-biconexas tem uma grade simétrica m-por-n?

Exercícios da aula 19 (caminhos de custo mínimo)

E19.1  Mostre como o algoritmo de busca em largura (que atua sobre um digrafo sem custos) pode ser usado para calcular um caminho mínimo num digrafo com custos inteiros estritamente positivos nos arcos.  (Sugestão: Subdivida os arcos.)  Estime o consumo de tempo do seu algoritmo.

E19.2  Multiplicar o custo de cada arco de um digrafo por uma constante estritamente- positiva não muda a solução do problema dos caminhos mínimos (ou seja, os caminhos que eram mínimos continuam mínimos). Certo ou errado?

E19.3  Somar uma constante estritamente positiva ao custo de cada arco de um digrafo não muda a solução do problema dos caminhos mínimos (ou seja, os caminhos que eram mínimos continuam mínimos). Certo ou errado?

figs/mine/diwheel6-k-gray.png

E19.4  Considere o digrafo com custos nos arcos definido abaixo. O vetor pai[] dado em seguida é uma árvore radicada com raiz 0 no digrafo. O vetor x[] registra os custos dos caminhos com origem 0 na árvore.

0-2 0-3 0-4 2-4 3-4 3-5 1-4 4-5 5-1 1-2
 .7  .2  .8  .1  .7  .1  .1  .0  .3  .3
    v     0   1   2   3   4   5
pai[v]    0   5   0   0   0   3
  x[v]   .0  .6  .7  .2  .8  .3 

Essa árvore radicada é uma SPT?  (Responda sem executar um algoritmo de caminhos mínimos.)

E19.5  Considere um digrafo com custos positivos nos arcos.  Seja s um vértice do digrafo e v-w um arco.  Mostre que d(s,v) + cvw  ≥  d(s,w), sendo cvw o custo de v-w.  Deduza daí que d(s,v) + d(v,t) ≥ d(s,t) para quaisquer vértices s, vt.

Exercícios da aula 20 (caminhos de custo mínimo)

E20.1  A seguinte tabela promete dar as distâncias entre os vértices A,B,C e D de um grafo com custos positivos nas arestas. (Note que o grafo não é dado.)

         A   B   C    D
     A   0  53  54   48
     B  53   0  18  101
     C  54  18   0   12
     D  48 101  12    0

As distâncias estão corretas?  Corrija a tabela se necessário.  Construa um grafo com vértices A, B, C, D e custos nas arestas que seja consistente com a tabela corrigida. Procure construir um grafo com o menor número possível de arestas.  Faça uma tabela que indique em cada posição (i,j) qual o primeiro vértice no caminho mínimo de i para j

E20.2  Seja G o digrafo com custos nos arcos descrito a seguir.  Seja T a árvore radicada com raiz 0 cujos arcos são  0-1 1-2 1-3 .  Seja F a franja de T.  Faça uma lista dos arcos de F. Dê todos os caminhos em T + F que começam em 0 e terminam fora de T.  Destaque os caminhos de custo mínimo.

0-1 0-5 1-2 1-3 2-5 2-6 3-6 5-1 5-4 5-6 6-3 6-4
 .1  .6  .1  .2  .5  .5  .5  .1  .0  .3  .2  .2

E20.3  Aplique o algoritmo de Dijkstra com vértice inicial 0 ao seguinte digrafo com custos nos arcos:

0-1 1-2 2-3 3-4 4-5 0-2 0-5
 .1  .1  .1  .1  .1  .3  .6

E20.4  Mostre que a função DIGRAPHsptD0() (implementação ingênua do algoritmo de Dijkstra) consome VA unidades de tempo no pior caso.

Exercícios da aula 21 (algoritmo de Dijkstra)

E21.1  A tabela define um digrafo com custos positivos nos arcos.  Segue o vetor de pais de uma árvore radicada T com raiz 0 e, para cada vértice v, o custo x[v] do único caminho em T que vai de 0v.  A árvore T é uma SPT?  Explique detalhadamente.

0-1 1-2 2-3 4-3 3-5 3-0 0-5 5-4 1-4 4-2 5-1 
.41 .51 .50 .36 .38 .45 .29 .21 .32 .32 .29 
    v     0    1   2   3   4   5
pai[v]    0    0   4   4   5   0
  x[v]   .0  .41 .82 .86 .50 .29

E21.2  Escreva uma função que receba um digrafo G com custos positivos nos arcos e uma árvore radicada T em G e diga se T é uma SPT de G.

SOLUÇÃO:

boolean isSPT( Digraph G, Vertex *pai) {
   int *x = malloc( G->V * sizeof (double));
   double INFINITO = somaTodosOsCustos( G);
   for (v = 0; v < G->V; v++) x[v] = INFINITO;
   for (s = 0; s != pai[s]; s = pai[s]) ;
   /* s é a raiz da árvore */
   x[s] = 0.0;
   distsR( G, pai, s, x);
   /* para cada w, x[w] é o custo do caminho 
      de s a w na árvore */
   for (v = 0; v < G->V; v++) 
      for (a = G->adj[v]; a != NULL; a = a->next)
         if (!(x[v] + a->cost >= x[w])) {
            free( x);
            return FALSE;
         }
   free( x);
   return TRUE;
}

/* Supõe que x[v] é a distância de s a v na árvore.
   Para cada descendente w de v na árvore, armazena 
   em x[w] a distância de s a w na árvore.
*/
void distsR( Digraph G, Vertex *pai, Vertex v, double *x) {
   for (a = G->adj[v]; a != NULL; a= a->next) 
      if (pai[a->w] == v) {
         x[a->w] = x[v] + a->cost;
         distsR( G, pai, a->w, x[a->w]);
      }
}

Se T não for maximal (ou seja, se T não contiver todos os vértices que estão ao alcance de s em G), a resposta será FALSE.

E21.3  Seja G o digrafo com custos nos arcos descrito a seguir.  Seja T a árvore radicada com raiz 0 cujos arcos são  0-1 1-2 1-3 .  Seja F a franja de T.  Faça uma lista dos arcos de F. Dê todos os caminhos em T + F que começam em 0 e terminam fora de T.  Destaque os caminhos de custo mínimo.

0-1 0-5 1-2 1-3 2-5 2-6 3-6 5-1 5-4 5-6 6-3 6-4
 .1  .6  .1  .2  .5  .5  .5  .1  .0  .3  .2  .2

E21.4  Aplique o algoritmo de Dijkstra com vértice inicial 0 ao seguinte digrafo com custos nos arcos:

0-1 1-2 2-3 3-4 4-5 0-2 0-5
 .1  .1  .1  .1  .1  .3  .6

E21.5  Considere o digrafo com custos nos arcos definido a seguir. Uma certa iteração da implementação DIGRAPHsptD0() do algoritmo de Dijkstra começa com a árvore radicada cujos arcos são 6-16-2. Dê o estado dos vetores pai[] e dist[] no início da próxima iteração.

6-1 6-2 1-2 4-3 5-3 0-3 1-4 2-4 0-4 1-5 6-0 1-0 2-0 
1.5 1.6 2.5 2.5 1.5 1.5 4.4 4.2 1.1 4.5 4.7 3.0 3.0

E21.6  Suponha dado um digrafo G com custos positivos nos arcos, um vértice s, e a distância dist[v] de sv para cada vértice v.  Decida se podemos diminuir o custo de um dado arco v-w sem que o vetor de distâncias dist[] sofra alterações.

E21.7  Suponha dado um digrafo G com custos positivos nos arcos, um vértice s, e a distância dist[v] de sv para cada vértice v.  Decida se podemos aumentar o custo de um dado arco v-w sem que o vetor de distâncias dist[] sofra alterações.

E21.8  Considere as implementações DIGRAPHsptD1(), DIGRAPHsptD2() e DIGRAPHsptD3() do algoritmo de Dijkstra?  Como começa cada iteração dessas implementações?

E21.8a  Explique informalmente, em suas próprias palavras, qual a diferença entre as implementações DIGRAPHsptD2() e DIGRAPHsptD3() do algoritmo de Dijkstra.

E21.9  Custos nos vértices.  Suponha dado um digrafo com custos positivos associados aos vértices. O custo de um caminho num tal digrafo é a soma dos custos dos vértices do caminho. Quero encontrar um caminho de custo mínimo dentre os que começam num vértice s e terminam num vértices t.  Reduza esse problema ao problema de encontrar um caminho num digrafo com custos nos arcos.  (Sugestão: Troque cada vértice v com custo c por um arco v0-v1 com custo c. Os arcos que entravam em v passam a entrar em v0 e os que saíam de v passam a sair de v1.

Exercícios da aula 22 (árvores geradoras e MST)

E22.1  Seja G um grafo conexo com custos nas arestas. Seja T uma MST de G.  Mostre que T continua sendo uma MST de G se o custo de cada aresta for multiplicado por um mesmo número m ≥ 0.  (A propriedade continua válida se m for estritamente negativo?)  Mostre que T continua sendo uma MST de G se somarmos um mesmo número s, positivo ou negativo, ao custo de cada aresta. 

Cuidado! Muita gente errou essa questão simples. É uma péssima ideia usar o condição dos circuitos (condição insere-remove) para resolver essa questão!

SOLUÇÃO DA PARTE 1: Para cada aresta e, seja c(e) o custo da aresta.  Defina um novo sistema de custos nas arestas: o custo de cada aresta e é agora f(e) := mc(e).  Vamos mostrar que T é uma MST para o grafo G com custos f.

PROVA: É claro que T é uma árvore geradora. Resta mostrar que o custo f(T) de T é mínimo. Seja S uma árvore geradora qualquer e vamos mostrar que f(T) ≤ f(S):

f(T) = ∑(f(e) : e em T)
  = ∑(mc(e) : e em T)
  = m ∑(c(e) : e em T)
  = m c(T)
  m c(S)
  = m ∑(c(e) : e em S)
  = ∑(m c(e) : e em S)
  = ∑(f(e) : e em S)
  = f(S).

(Note como nossas contas dependem da hipótese m ≥ 0.)

SOLUÇÂO DA PARTE 2: Defina um novo sistema de custos nas arestas: o custo de cada aresta e é agora f(e) := c(e) + s.  Vamos mostrar que T é uma MST para o grafo G com custos f.

PROVA: É claro que T é uma árvore geradora. Resta mostrar que o custo f(T) de T é mínimo. Seja S uma árvore geradora qualquer e vamos mostrar que f(T) ≤ f(S):

f(T) = ∑(f(e) : e em T)
  = ∑(c(e) + s : e em T)
  = (∑(c(e) : e em T)) + (V−1)s
  = c(T) + (V−1)s
  c(S) + (V−1)s
  = (∑(c(e) : e em S)) + (V−1)s
  = ∑(c(e) + s : e em S)
  = ∑(f(e): e em S)
  = f(S),

sendo V o número de vértices de G.  A prova depende do seguinte fato: toda árvore geradora de G tem exatamente V−1 arestas.

Sedgewick-Wayne/trace-of-prims-algorithm-lazy-version-x.png

E22.2  Aplique o certificado de minimalidade baseado em circuitos ao grafo da figura. Depois, aplique o certificado de minimalidade baseado em cortes.

     4-5 4-7 5-7 0-7 1-5 0-4 2-3 1-7 0-2 1-2 1-3 2-7 6-2 3-6 6-0 6-4 
     .35 .37 .28 .16 .32 .38 .17 .19 .26 .36 .29 .34 .40 .52 .58 .93

SOLUÇÃO: O custo da aresta 5-1 é ≥ que o custo de qualquer aresta do circuito 5-1-7-5. O custo da aresta 1-3 é ≥ que o custo de qualquer aresta do circuito 1-3-2-0-7-1. Etc. etc.

O custo da aresta 5-7 é ≤ que o custo de qualquer aresta do corte 5-1 5-7 4-7 4-0 4-6. Etc. etc.

E22.3  Mostre que SPTs e MSTs de grafos conexos podem ser muito diferentes. Dê um exemplo de um grafo G com custos positivos nas arestas e uma MST T nesse grafo que tenha a seguinte propriedade:  para todo vértice s existe um vértice t tal que a distância de s a t em G é diferente da distância de s a t em T.  (Dica: existem exemplos com 4 vértices apenas.)

E22.4  Suponha que todas as arestas de um grafo conexo têm o mesmo custo.  Mostre que toda árvore geradora do grafo é uma MST.

E22.5  Suponha que os custos das arestas de um grafo conexo são distintos entre si (ou seja, não há duas arestas com o mesmo custo). Mostre que o grafo tem uma única MST.

E22.6  Seja G um grafo conexo com custos nas arestas. Suponha que uma aresta e de G é mais cara que qualquer outra aresta de G.  É verdade que nenhuma MST de G contém e?

E22.7  Suponha que os custos das arestas de um grafo conexo são distintos entre si. Seja C um circuito qualquer. É verdade que a aresta mais barata de C pertence à (única) MST do grafo? 

E22.8  Como encontrar uma árvore geradora de custo máximo num grafo conexo com custos nas arestas?

E22.9  Seja a uma aresta de custo mínimo em um grafo G com custos nas arestas.  É verdade que a pertence a alguma MST de G?  É verdade que a pertence a toda MST de G?

E22.10  Seja C um circuito em um grafo conexo G com custos nas arestas. Suponha que uma aresta e de C é mais cara que qualquer outra aresta de C.  É verdade que nenhuma MST de G contém e?

Exercícios da aula 23 (algoritmo de Prim)

E23.1  Compare o algoritmo de Prim com o algoritmo de Dijkstra para o problema da SPT (caminhos de custo mínimo). Quais as diferenças? Quais as semelhanças?

SOLUÇÃO: O conceito de preço de um vértice é diferente nos dois algoritmos. O resto é praticamente igual.

E23.2  Compare o código de GRAPHmstP1() com o de DIGRAPHsptD1() para o problema da SPT (caminhos de custo mínimo). Quais as diferenças? Quais as semelhanças?

SOLUÇÃO: Apenas duas linhas de código são diferentes! O resto é igual!

E23.3  Escreva uma versão simplificada da função GRAPHmstP1() que receba um grafo conexo e devolva o custo — apenas o custo — de uma MST do grafo.  Escreva código enxuto, sem variáveis supérfluas.

E23.4  Modifique o código de GRAPHmstP1() de modo a imprimir um rastreamento da execução da função.

E23.5  Aplique a função GRAPHmstP1() ao grafo com custos nas arestas descrito abaixo. Faça o rastreamento da execução da função.

0-2 2-4 4-1 1-3 3-0 2-3 0-4
0.8 0.2 0.3 0.0 0.8 0.0 0.4

SOLUÇÃO: Será que assim está certo?

pai[]       pr[] (x 10)        frj[]
0 1 2 3 4   0  1  2  3  4      0 1 2 3 4

0 - - - -   0  *  8  8  4      0 - 0 0 0
0 - - - 0   0  3  2  8  4      0 4 4 0 0
0 - 4 - 0   0  3  2  0  4      0 4 4 2 0
0 - 4 2 0   0  0  2  0  4      0 3 4 2 0
0 3 4 2 0   0  0  2  0  4      0 3 4 2 0

Exercícios da aula 24 (algoritmo de Kruskal)

E24.1  O que acontece se as últimas linhas de GRAPHmstK0() forem trocadas pelo código a seguir?

for (v = 0; v < G->V; v++) 
   if (chefe[v] == chefe[w0])
      chefe[v] = chefe[v0];

E24.2  Aplique a função GRAPHmstK1() ao grafo com custos descrito a seguir. Faça uma figura da estrutura union-find definida por ch[].

3-4 2-4 5-6 0-2 0-3 2-3 4-5 4-6 1-2 3-5 1-6 1-4
 .2  .3  .4  .5  .8 1.0 1.2 1.4 1.6 1.8 2.6 3.0

SOLUÇÃO: Seguem os vetors ch[], sz[] e mst[] no início das sucessivas iterações da função GRAPHmstK1():

ch[]              sz[]              mst[]
0 1 2 3 4 5 6     0 1 2 3 4 5 6     0   1   2   3   4   5   
                                                           
0 1 2 3 4 5 6     1 1 1 1 1 1 1                            
0 1 2 3 3 5 6     1 1 1 2 1 1 1     3-4                    
0 1 3 3 3 5 6     1 1 1 3 1 1 1     3-4 2-4                
0 1 3 3 3 5 5     1 1 1 3 1 2 1     3-4 2-4 5-6            
3 1 3 3 3 5 5     1 1 1 4 1 2 1     3-4 2-4 5-6 0-2        
3 1 3 3 3 3 5     1 1 1 6 1 2 1     3-4 2-4 5-6 0-2 4-5    
3 3 3 3 3 3 5     1 1 1 7 1 2 1     3-4 2-4 5-6 0-2 4-5 2-1

Veja a evolução da estrutura union-find à medida que arestas são acrescentadas à MST:

                   3
                              
                                     
                4  2  0  5  1
                          
                         6

      3-4
                   3
                 __|
                |        
                4  2  0  5  1
                         
                         6
                
      2-4
                   3
                 __|
                |  |      
                4  2  0  5  1
                         
                         6

      5-6
                   3
                 __|
                |  |      
                4  2  0  5  1
                         |
                         6

      0-2
                   3
                 __|__
                |  |  |    
                4  2  0  5  1
                         |
                         6

      4-5
                   3
                 __|_____
                |  |  |  |  
                4  2  0  5  1
                         |
                         6
                          
      2-1
                   3
                 __|________
                |  |  |  |  |
                4  2  0  5  1
                         |
                         6

E24.3  Escreva uma versão simplificada da função GRAPHmstK1() que receba um grafo G possivelmente desconexo e devolva o custo — apenas o custo — de uma floresta geradora maximal de custo mínimo de G.  Escreva o código do union-find tão embutido quanto possível no código de sua função.  Escreva código enxuto, sem variáveis supérfluas.

E24.4  [Sedgewick 20.18] Vetor de pais.  Escreva uma função GRAPHmstK1_pai() que invoque GRAPHmstK1() e depois calcule o vetor de pais pai[] da árvore gradora que GRAPHmstK1() depositou no vetor mst[].

SOLUÇÃO do Pedro:

Edge mst[1000-1];
Vertex pai[1000];

void GRAPHmstK1_pai( Graph G)
{
   int k;
   GRAPHmstK1( G);
   /* mst[0..V-1] é o conjunto de arestas de uma MST
      de G. Temos mst[k].v < mst[k].w para cada k
      em virtude da função GRAPHedges().
   */
   for (k = 0; k < G->V-1; ++k) 
      pai[mst[k].w] = mst[k].v;
   pai[0] = 0;
}

Eu acho que está certo. O que você acha?

Pensando melhor, acho que não está certo. Você tem um contraexemplo?

Exercícios da aula 25 (caminhos em DAGs)

E25.1  Dê um caminho mínimo do vértice 0 ao vértice 3 no DAG com 4 vértices e custos nos arcos especificado a seguir. Adote o ordenamento topológico  0 1 2 3 4.

0-1  0-2  1-3  2-3
1.1  2.1  3.1  1.8  

E25.2  O seguinte exemplo mostra que a função DAGminPath() não pode ser aplicado a digrafos que têm ciclos. Suponha que queremos determinar as distâncias a partir do vértice 0 no digrafo com custos nos arcos definido abaixo.  Verifique que a função produz resultados incorretos se os vértices forem processados na ordem  0 1 2 3 .

0-2 2-1 2-3 1-3 3-2
0.1 0.1 0.9 0.1 0.1

E25.3  Modifique o código de DAGminPath() para que a função calcule uma SPT (ou seja, uma árvore radicada de caminhos mínimos) com raiz s.

E25.4  Calcule caminhos mínimos a partir do vértice 0 no DAG descrito a seguir. Use o ordenamento topológico  0 3 2 4 5 1 .

0-2  0-4  0-3  3-4  3-5  2-1  2-4  4-1  4-5  5-1
2.0  3.0  4.0 -2.0  1.0  1.0 -1.0  0.0  1.0  2.0

E25.5  PERT/CPM.  O seguinte problema surge naturalmente na administração de grandes projetos de engenharia.  Dado um DAG com custos positivos nos arcos (os custos representam o tempo da execução de uma parte do projeto), encontrar um caminho máximo dentre os máximos, ou seja, um caminho C tal que nenhum outro caminho (quaisquer que sejam sua origem e seu término) tenha custo maior que o de C. Adapte o código de DAGmaxPath() para resolver o problema.