Introducción a los Grafos y Algoritmos
Introducción a los Grafos y Algoritmos
Román Castellarin
1
Definiciones básicas
Representación
DFS/BFS
Aplicaciones
Disjoint Sets
MST
Dijkstra
Floyd-Warshall
2
¿Qué son?
Puntitos y rayitas.
Más formalmente, un grafo G = (V, E) consiste de un conjunto V de vértices,
y un conjunto E de aristas que conectan cada una dos vértices.
Generalmente llamamos N = |V| y M = |E|.
3
Grafos
4
Grafos
10
5
25
30
7
3
5
Grafos
6
Grafos
7
Grafos
Bucle
Aristas paralelas
8
Ejemplos
9
Ejemplos
cin>>N>>M;
forn(i, M){
int a, b; 0
cin >> a >> b; 3
E.push_back({a,b}); 1
}
13
Matriz de Adyacencia
Consiste en una matriz A de NxN tal que A[i][j] = 1 sii hay una arista (i, j)
int A[MAXN][MAXN]; 2
4
0 1 0 1 0
0 0 0 0 0
0 0 0 1 1 0
3
0 0 0 0 1
1
1 0 0 0 0
14
Matriz de Adyacencia
int N, M;
int A[MAXN][MAXN];
… 2
cin>>N>>M; 4
forn(i, M){
int a, b;
cin >> a >> b;
A[a][b] = 1; 0
} 3
15
Lista de Adyacencias
0: 1, 3
1: 0
3
2: 3, 4
1
3: 4
4: 0
16
Lista de Adyacencias
int N, M;
vector<int> G[MAXN];
… 2
cin>>N>>M; 4
forn(i, M){
int a, b;
cin >> a >> b;
G[a].push_back(b); 0
} 3
17
Representaciones
Un camino u-w es una secuencia de vértices u = v0, v1, .., vn= w adyacentes.
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
color[v] = GRIS; 4
53
Aplicaciones 54
Orden topológico
Ejemplo: 4
2 2 3 4 0 1
0
posible toposort
3
1
55
Orden topológico
Teorema:
58
Kosaraju's
59
4
Kosaraju's
1
Supongamos que obtenemos: 2
24103 0 3
0 3
60
4
Kosaraju's
1
Supongamos que obtenemos: 2
24103 0 3
0 3
61
4
Kosaraju's
1
Supongamos que obtenemos: 2
24103 0 3
0 3
62
4
Kosaraju's
1
Supongamos que obtenemos: 2
24103 0 3
0 3
63
2-SAT
1-SAT es trivial
2-SAT es interesante!
Ejemplo:
(a∨¬b) ∧ (¬a∨b) ∧ (¬a∨¬b) ∧ (a∨¬c)
Resulta en las siguientes implicancias:
¬a➝¬b
b➝a
a➝b
¬b➝¬a
a➝¬b
b➝¬a
¬a➝¬c
c➝a ejemplo extraído de [Link] 66
2-SAT
Ejemplo:
(a∨¬b) ∧ (¬a∨b) ∧ (¬a∨¬b) ∧ (a∨¬c)
Resulta en las siguientes implicancias:
¬a➝¬b
b➝a
a➝b
¬b➝¬a
a➝¬b
b➝¬a
¬a➝¬c
c➝a ejemplo extraído de [Link] 67
Puentes
● Tirar un DFS, orientar las aristas en el sentido en las cual las recorremos
● Hallar las SCCs del grafo
● Una arista u-v es un puente sii u y v pertenecen a SCCs distintas
68
Árbol
Generador
Mínimo
(MST)
esto no es un
MST
69
MST
● es conexo
● es acíclico
70
MST
1 10 1 10 1 10 1 10
5 5 5 5
8 8 8 8
7 4 7 4 7 4 7 4
3 3 3 3
74
Union Find
struct disjoint_sets{
void init(int n){
[Link]();
[Link](n, -1);
}
int find(int x){
return v[x] == -1 ? x : v[x] = find(v[x]);
}
int join(int x, int y){
x = find(x); y = find(y);
if( x != y )
v[x] = y;
}
vector<int> v;
}; 75
Kruskal
// Sea E la lista de aristas {u, v, peso} de un grafo conexo
// Sea S la estructura de conjuntos disjuntos
sort([Link](), [Link]());
for(auto &e: E) 1 7
if( [Link](e.u) != [Link](e.v) ) 5
Ans += [Link];
else [Link](e.u, e.v);
8
10 15
cout << "Peso del MST: " << Ans << endl;
76
Kruskal
// Sea E la lista de aristas {u, v, peso} de un grafo conexo
// Sea S la estructura de conjuntos disjuntos
sort([Link](), [Link]());
for(auto &e: E) 1 7
if( [Link](e.u) != [Link](e.v) ) 5
Ans += [Link];
else [Link](e.u, e.v);
8
10 15
cout << "Peso del MST: " << Ans << endl;
77
Kruskal
// Sea E la lista de aristas {u, v, peso} de un grafo conexo
// Sea S la estructura de conjuntos disjuntos
sort([Link](), [Link]());
for(auto &e: E) 1 7
if( [Link](e.u) != [Link](e.v) ) 5
Ans += [Link];
else [Link](e.u, e.v);
8
10 15
cout << "Peso del MST: " << Ans << endl;
78
Kruskal
// Sea E la lista de aristas {u, v, peso} de un grafo conexo
// Sea S la estructura de conjuntos disjuntos
sort([Link](), [Link]());
for(auto &e: E) 1 7
if( [Link](e.u) != [Link](e.v) ) 5
Ans += [Link];
else [Link](e.u, e.v);
8
10 15
cout << "Peso del MST: " << Ans << endl;
79
Kruskal
// Sea E la lista de aristas {u, v, peso} de un grafo conexo
// Sea S la estructura de conjuntos disjuntos
sort([Link](), [Link]());
for(auto &e: E) 1 7
if( [Link](e.u) != [Link](e.v) ) 5
Ans += [Link];
else [Link](e.u, e.v);
8
10 15
cout << "Peso del MST: " << Ans << endl;
80
Análisis
81
Distancias en
grafos
ponderados
82
Dijkstra 83
Dijkstra
84
Dijkstra
struct hedge{ La estructura hedge guarda "medio
int v, d; arco": la longitud y el vértice final.
bool operator<(const arco &otro) const {
return d > otro.d;
} Para insertar el arco u→v con peso d:
}; G[u].push_back({v, d});
D[4] = -1 3
30
void Dijkstra(int inicial){ P[4] = -1 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = -1
continue; 3 P[2] = -1 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = -1
} D[0] = -1 P[1] = -1
} P[0] = -1
86
D[3] = -1
Dijkstra P[3] = -1
D[4] = -1 3
30
void Dijkstra(int inicial){ P[4] = -1 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = -1
continue; 3 P[2] = -1 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = -1
} D[0] = 0 P[1] = -1
} P[0] = -1
87
D[3] = -1
Dijkstra P[3] = -1
D[4] = -1 3
30
void Dijkstra(int inicial){ P[4] = -1 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = -1
continue; 3 P[2] = -1 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = -1
} D[0] = 0 P[1] = -1
} P[0] = -1
88
D[3] = -1
Dijkstra P[3] = -1
D[4] = -1 3
30
void Dijkstra(int inicial){ P[4] = -1 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = -1
continue; 3 P[2] = -1 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 15
} D[0] = 0 P[1] = 0
} P[0] = -1
89
D[3] = -1
Dijkstra P[3] = -1
D[4] = -1 3
30
void Dijkstra(int inicial){ P[4] = -1 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 15
} D[0] = 0 P[1] = 0
} P[0] = -1
90
D[3] = -1
Dijkstra P[3] = -1
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 15
} D[0] = 0 P[1] = 0
} P[0] = -1
91
D[3] = -1
Dijkstra P[3] = -1
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 15
} D[0] = 0 P[1] = 0
} P[0] = -1
92
D[3] = 33
Dijkstra P[3] = 4
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 15
} D[0] = 0 P[1] = 0
} P[0] = -1
93
D[3] = 33
Dijkstra P[3] = 4
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 15
} D[0] = 0 P[1] = 0
} P[0] = -1
94
D[3] = 33
Dijkstra P[3] = 4
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = -1
priority_queue<hedge> Q; P[5] = -1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 12
} D[0] = 0 P[1] = 2
} P[0] = -1
95
D[3] = 33
Dijkstra P[3] = 4
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = 30
priority_queue<hedge> Q; P[5] = 2
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 12
} D[0] = 0 P[1] = 2
} P[0] = -1
96
D[3] = 30
Dijkstra P[3] = 2
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = 30
priority_queue<hedge> Q; P[5] = 2
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 12
} D[0] = 0 P[1] = 2
} P[0] = -1
97
D[3] = 30
Dijkstra P[3] = 2
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = 30
priority_queue<hedge> Q; P[5] = 2
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 12
} D[0] = 0 P[1] = 2
} P[0] = -1
98
D[3] = 30
Dijkstra P[3] = 2
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = 22
priority_queue<hedge> Q; P[5] = 1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 12
} D[0] = 0 P[1] = 2
} P[0] = -1
99
D[3] = 30
Dijkstra P[3] = 2
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = 22
priority_queue<hedge> Q; P[5] = 1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 12
} D[0] = 0 P[1] = 2
} P[0] = -1
100
D[3] = 25
Dijkstra P[3] = 5
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = 22
priority_queue<hedge> Q; P[5] = 1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 12
} D[0] = 0 P[1] = 2
} P[0] = -1
101
D[3] = 25
Dijkstra P[3] = 5
D[4] = 3 3
30
void Dijkstra(int inicial){ P[4] = 0 3 D[5] = 22
priority_queue<hedge> Q; P[5] = 1
[Link]({inicial, 0}); 4
20
D[inicial] = 0; 50 5
while(not [Link]()){
20
auto c = [Link](); [Link]();
if( D[c.v] < c.d ) 2 D[2] = 10
continue; 3 P[2] = 0 10
for(auto &e: G[c.v]) 2
if( D[e.v] == -1 or D[e.v] > c.d + e.d ){ 10
D[e.v] = c.d + e.d;
P[e.v] = c.v;
1
[Link]({e.v, D[e.v]});
0 15
} D[1] = 12
} D[0] = 0 P[1] = 2
} P[0] = -1
102
Análisis
103
Floyd Warshall 104
Floyd-Warshall
105
Floyd-Warshall
106
Floyd-Warshall
D[i][j][k] :=
longitud de un i-j camino mínimo cuyos vértices intermedios están en 1..k
107
Floyd-Warshall
Guardaremos en una matriz D de NxN la distancia más corta para todo par
de vértices.
INF representa un número muy grande.
forn(k, N)
forn(i, N)
forn(j, N)
D[i][j] = min(D[i][j], D[i][k] + D[k][j]);
108
Floyd-Warshall
forn(k, N)
forn(i, N)
forn(j, N)
if( D[i][j] > D[i][k] + D[k][j] ){
D[i][j] = D[i][k] + D[k][j];
Next[i][j] = Next[i][k];
}
109
Gracias! 110