20
TREINAMENTO PARA COMPETIÇÕES DE PROGRAMAÇÃO GRAFOS - PARTE III SINGLE-SOURCE SHORTEST PATHS: DIJKSTRA E BELLMAN-FORD Murilo Adriano Vasconcelos http://murilo.wordpress.com

Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Embed Size (px)

DESCRIPTION

Aula sobre os algoritmos de Dijkstra e Bellman-Ford pra turma de Tópicos Avançados de Programação com código em C++.

Citation preview

Page 1: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

TREINAMENTO PARA COMPETIÇÕES DE PROGRAMAÇÃO

GRAFOS - PARTE IIISINGLE-SOURCE SHORTEST PATHS:

DIJKSTRA E BELLMAN-FORD

Murilo Adriano Vasconceloshttp://murilo.wordpress.com

Page 2: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O problema

• Dado um grafo ponderado G(V, E), onde as arestas tem custos positivos, queremos saber qual o custo do menor caminho de um vértice origem u ∈ V para todos os outros vértices v ∈ V.

Page 3: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O algoritmo de Dijkstraconst int MAXV = 1000; // número máximo de vérticesconst int INF = 0x3f3f3f3f; // cuidado com esse valorlist< pair<int, int> > grafo[MAXV]; // lista de adjacênciaint dist[MAXV]; // a resposta ficará neste vetorint visited[MAXV], N; // N é a quantidade de vértices atual

void leitura() {

cin >> N >> m; // quantidade de vertices e arestasint de, para, custo;// limpa o grafofor (int i = 0; i < N; ++i) g[i].clear();

// leitura da entradafor (int i = 0; i < m; ++i) {

cin >> de >> para >> custo;g[de].push_back(make_pair(para, custo));

}}

Page 4: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O algoritmo de Dijkstra

void dijkstra(int origem){

for (int i = 0; i < N; ++i) {dist[i] = INF;visited[i] = false;

}

// nossa heap de máximo onde: first = custo, // second = verticepriority_queue< pair<int, int> > pq;pq.push(make_pair(0, origem));dist[origem] = 0; // distancia da origem pra ela

// mesma é 0

pair<int, int> atual;list< pair<int, int> >::iterator it;

Page 5: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O algoritmo de Dijkstrawhile (!pq.empty()) {

atual = pq.top();pq.pop();

int custo = -atual.first; // nao esqueça do ‘-’!int v = atual.second;

if (visited[v]) continue; // já processamos elevisited[v] = true; // se cheguei aqui, o menor custo

// de origem para v já foi calculado

// para cada aresta, tentamos fazer a relaxaçãofor (it = g[v].begin(); it != g[v].end(); ++it) {

if (dist[it->second] > w + it->first) { dist[it->second] = w + it->first; pq.push(make_pair(-dist[it->second], it->second)); }

}}

} // dijkstra

Page 6: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O algoritmo de Dijkstra

• Inicialmente, colocamos na heap, o vértice de origem com o custo 0 e dizemos que o custo da origem para origem é 0

• Em seguida, para cada elemento v com o menor custo (top() na priority_queue), tentamos relaxar (diminuindo) o custo dos seus vizinhos

• Se o custo de algum vértice u for maior que o custo de v mais o custo da aresta que liga o v a u, diminuímos o custo de u para este valor

Page 7: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Dijkstra - demonstração

Page 8: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Dijkstra - análise

• Complexidade O(|E| log |V|)

• |V| = 1000, |E| = 100.000 < 10^6 operações (feasible)

• Comparativo com Floyd-Warshall O(|V|^3)

• |V| = 1000, 10^9 operações (geralmente unfeasible)

Page 9: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Outro problema

• Dado um grafo ponderado G(V, E), onde as arestas podem ter custos negativos, queremos saber qual o custo do menor caminho de um vértice origem u ∈ V para todos os outros vértices v ∈ V.

Page 10: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Usar o Dijkstra?

• Seja G, este grafo:

0 1 3

2

4102

-1 -4

1

Page 11: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Usar o Dijkstra?

Seja G, este grafo:

0 1 3

2

4102

-1 -4

1

Qual a menor distância entre 0 e 4?

Page 12: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Usar o Dijkstra?

Não podemos usar o Dijkstra, pois o grafo contém um ciclo negativo.

0 1 3

2

4102

-1 -4

1

Podemos ficar infinitamente neste ciclo pois o custo sempre diminuirá

Page 13: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O algoritmo Bellman-Ford

• O algoritmo de Bellman-Ford encontra o menor caminho entre um vértice origem e todos os outros se o grafo não tiver ciclos negativos

• Se o grafo tiver ciclos negativos, o algoritmo serve para detectá-los

Page 14: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O algoritmo Bellman-Ford

• Utiliza a representação de lista de arestas

• Faz a relaxação utilizando a desigualdade triangular |V| - 1 vezes

• Se após |V| - 1 relaxações, ainda conseguirmos diminuir o custo de algum vértice, o grafo contém ciclos negativos

Page 15: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O algoritmo Bellman-Fordconst int MAXV = 1000; // número máximo de vérticesconst int INF = 0x3f3f3f3f; // cuidado com esse valor

struct aresta { int u, v, w; }; // de, para, custovector<aresta> grafo; // pode ser um array se

// soubermos o máximo de arestasint custo[MAXV], N, E; // custo, vértices, arestas

void le(){

cin >> N >> E; // le a quant. de vértices e arestas

grafo.clear();aresta ar;for (int i = 0; i < E; ++i) {

cin >> ar.u >> ar.v >> ar.w; // de, para, custografo.push_back(ar);

}}

Page 16: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O algoritmo Bellman-Ford

bool bellan_ford(int origem){

for (int i = 0; i < V; ++i) custo[i] = INF;custo[origem] = 0;for (int i = 0; i < V - 1; ++i) { // até V - 1

for (int j = 0; j < E; ++j) {int u = grafo[j].u;int v = grafo[j].v;int w = grafo[j].w;

// relaxaçãoif (custo[v] > custo[u] + w) {

custo[v] = custo[u] + w;}

}}

Page 17: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

O algoritmo Bellman-Ford

// checagem de ciclos de custo negativofor (int j = 0; j < E; ++j) {

int u = grafo[j].u;int v = grafo[j].v;int w = grafo[j].w;

// se ainda é possível diminuir o custo// é porque sempre vai ter como (ciclo negativo)if (custo[v] > custo[u] + w) {

return false; // ciclo encontrado}

}

return true; // nenhum ciclo negativo

} // bellman_ford()

Page 18: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Bellman-Ford - análise

• Complexidade O(VE)

• Loop de fora V vezes, loop interno E vezes

Page 19: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Alguns Problemas

Dijkstra (UVA):341 - Non-Stop Travel929 - Number Maze

  1202 - Finding Nemo 10166 - Travel 10269 - Adventure of Super Mario 10278 - Fire Station 10389 - Subway 10603 - Fill 10801 - Lift Hopping 10986 - Sending email 11367 - Full Tank? 11377 - Airport Setup 11492 - Babel 11833 - Route Change 12138 - Chemical Plant

Bellman Ford (UVA): 558 - Wormholes 10557 - XYZZY 11280 - Flying to Fredericton

Page 20: Treinamento para Competições de Programacão - Single-Source Shortest Paths: Dijkstra e Bellman-Ford

Dúvidas?