Desafios de Programação

Semana 11

  • Conteúdo
    • Grafos
    • Atividades
Material Didático cedido pelo Professor Marcos Lage
Grafos
Introdução

Exemplo:

Grafos
Propriedades

Grafos podem ser:

Grafos
Propriedades

Voltando ao exemplo:

De acordo com as definições anteriores, o grafo do exemplo exibido acima é direcionado, sem presos, cíclio e não simples.

Grafos
Representação

O grafo do exemplo pode ser representado pelos conjuntos:

Grafos também podem ser representados através de matrizes de adjacência:

Grafos
Implementação

Um grafo pode ser implementado usando o código abaixo:

C/C++:

          
struct edge_s {
    int v;
    float weight;
};

struct graph_s {
    edge_s edges[MAX_NVERTICES][MAX_DEGREE];
    int degree[MAX_NVERTICES];
    float weight[MAX_NVERTICES];
    int nvertices;
    int nedges;
};
          
        

Grafos
Travessia
Grafos
Busca em largura

Em uma busca em largura, controlamos os vértices descobertos e processados através de uma estrutura de fila.

Pseudocódigo:

          
BFS(G, s)
    #initialize status, parent, and distance arrays;
    #initialize queue Q;
    Enqueue(Q, s)
    status[s] = DISCOVERED;
    while Q not empty:
        u = Dequeue(Q);
        #process vertex u;
        status[u] = PROCESSED;
        for each v adjacent to u:
            if {u, v} is a valid edge:
                #process edge {u, v};
                if status[v] == UNDISCOVERED:
                    Enqueue(Q, v);
                    status[v] = DISCOVERED;
                    distance[v] = distance[u] + 1;
                    parent[v] = u;
          
        

Grafos
Busca em largura

Em uma busca em profundidade, controlamos os vértices descobertos e processados através de uma estrutura de pilha.

Pseudocódigo:

          
DFS(G, s)
    #initialize status, parent and depth arrays;
    #initialize stack S;
    Push(S, s)
    status[s] = DISCOVERED;
    while S not empty:
        u = Pop(S);
        #process vertex u;
        status[u] = PROCESSED;
        for each v adjacent to u:
            if {u, v} is a valid edge:
                #process edge {u, v};
                if status[v] == UNDISCOVERED:
                    Push(S, v);
                    status[v] = DISCOVERED;
                    depth[v] = depth[u] + 1;
                    parent[v] = u;
          
        

Grafos
Ordenação topológica

Exemplo (ordem - $5,4,2,3,1,0$):

Grafos
Ordenação topológica

A ordenação topológica pode ser implementada usando o seguinte pseudocódigo:

Pseudocódigo:

          
TopSort(G)
    #initialize indegree, and sorted arrays;
    #initialize queue Q;
    for each v in G:
        if indegree[v] == 0: 
            Enqueue(Q, v)
    count = 0;
    while Q not empty:
        x = Dequeue(Q);
        sorted[count] = x;
        for each y adjacent to x:
            indegree[y]--;
            if indegree[y] == 0:
                Enqueue(Q, y)
        count++;
    #assert count equals number of vertices;
          
        

Grafos
Árvore geradora

Exemplo de árvore geradora mínima:

Grafos
Árvore geradora

A árvore geradora mínima pode ser implementada usando o algoritmo de Prim, apresentado abaixo:

Pseudocódigo:

          
Prim(G, start)
    #initialize intree, distance, and parent arrays;
    v = start;
    distance[start] = 0;
    while intree[v] == FALSE:
        intree[v] = TRUE;
        for each w adjacent to v:
            weight = weight of edge {v, w};
            if (distance[w] > weight) and (intree[w] == FALSE):
                parent[w] = v;
                distance[w] = weight;
        v = vertex not in tree, and min. distance
          
        

Observação:
Existem variações como, por exemplo, arvores geradoras máximas. Basta usar o algoritmo de Prim com pesos negativos.

Grafos
Caminho mais curto
Grafos
Caminho mais curto

O caminho mais curto pode ser implementada usando o algoritmo de Dijkstra, apresentado abaixo:

Pseudocódigo:

          
Dijkstra(G, start)
    #initialize intree, distance, and parent arrays;
    v = start;
    distance[start] = 0;
    while intree[v] == FALSE:
        intree[v] = TRUE;
        for each w adjacent to v:
            weight = weight of edge {v, w};
            if distance[w] > distance[v] + weight:
                distance[w] = distance[v] + weight;
                parent[w] = v;
        v = vertex not in tree, and min. distance
          
        

Grafos
Caminho mais curto

O tamanho do caminho mais curto pode ser implementada usando o algoritmo de Floyd-Warshall, apresentado abaixo:

Pseudocódigo:

          
FloydWarshall(G)
    for each vertex k in G:
        for each vertex i in G:
            for each vertex j in G:
                if G[i,k] + G[k,j] < G[i,j]:
                    G[i,j] = G[i,k] + G[k,j];
          
        

Grafos
Fluxo máximo
Grafos
Caminho mais curto

O fluxo máximo entre dois vértices pode ser implementado usando o algoritmo de Ford-Fulkerson, apresentado abaixo:

Pseudocódigo:

          
FordFulkerson(G, source, sink)
    max_flow = 0;
    while BFS(G, source, sink, parent):
        path_flow = MAX_VALUE;
        for each v in the path from skin to source:
            u = parent[v]
            path_flow = min(path_flow, G[u,v]);

        for each v in the path from sink to source:
            u = parent[v];
            G[u,v] -= path_flow;
            G[v,u] += path_flow;

        max_flow += path_flow;
          
        

Atividades
Sugestão de estudo

Leitura:

Exercícios:

Desafios de Programação

Semana 11

  • Conteúdo
    • Grafos
    • Atividades
Material Didático cedido pelo Professor Marcos Lage