2. Grafos en el Mundo Real
Existen muchos ejemplos de grafos en el
mundo real.
Tu puedes estar usando precisamente
ahora, uno de estos ejemplos, Internet.
Las redes interconectadas que forman
Internet son ejemplos comunes de un
grafo.
Mtl Lourdes Cahuich 2
3. Grafos en el Mundo Real
Las computadoras forman los nodos del
grafo.
Como no toda máquina está conectada a
cualquier otra máquina, estas ligas entre
máquinas también son parte del grafo.
Mtl Lourdes Cahuich 3
4. Grafos en el Mundo Real
Cada liga entre un par de computadoras
puede ser directa o indirecta, dependiendo
de si los mensajes pueden ser enviados
solamente en una dirección o en ambas.
Mtl Lourdes Cahuich 4
6. Definición de Grafos
Un grafo dirigido consiste en un conjunto
V de vértices o nodos y un conjunto E de
aristas (edges).
Cada arista tiene un nodo origen y un
nodo destino, y la arista puede ser
recorrida solamente de origen al destino.
Mtl Lourdes Cahuich 6
8. Definición de Grafos
Muchas de las operaciones básicas de un
grafo, giran alrededor de la existencia de
una ruta (path).
Una ruta es cualquier secuencia de nodos
conectados por las aristas.
El número de aristas en una ruta es la
longitud de la ruta
Mtl Lourdes Cahuich 8
9. Definición de Grafos
Por lo general, uno se enfrenta con grafos
no dirigidos en donde cada arista puede
ser recorrida en cualquier dirección.
Una arista no dirigida puede ser vista
como un par de aristas dirigidas, por lo
que nos enfocaremos en el caso dirigido
Mtl Lourdes Cahuich 9
11. Definición de Grafos
Tal vez la característica más atractiva de
los grafos es que éstos pueden ser
identificados visualmente, y las imágenes
de grafos son a menudo útiles para
motivar y describir propiedades
importantes.
Mtl Lourdes Cahuich 11
12. Definición de Grafos
Los algoritmos de grafos usualmente se
entienden mejor junto con algún dibujo
que muestra lo que el algoritmo realiza.
Mtl Lourdes Cahuich 12
14. Búsqueda por Niveles
(Breadth-First Search)
Un algoritmo búsqueda por niveles,
también conocido como búsqueda por
anchura (breadth-first search) es un
algoritmo que explora los nodos en un
grafo en el orden de la distancia de
aumento desde el nodo inicial.
Mtl Lourdes Cahuich 14
16. Búsqueda por Niveles
El algoritmo inicia examinando cada una
de las aristas salientes de este nodo
inicial.
Se van descubriendo nuevos nodos
cuando el algoritmo examina estas aristas
salientes.
Mtl Lourdes Cahuich 16
18. Búsqueda por Niveles
Estos nodos quot;descubiertosquot; son colocados
dentro de una cola.
Luego el algoritmo de búsqueda por
niveles, examina cada nodo descubierto
para determinar si se pueden alcanzar
nuevos nodos desde el nodo descubierto.
Mtl Lourdes Cahuich 18
19. Búsqueda por Niveles
Una vez que un nodo ha sido descubierto,
éste es colocado dentro de una cola de
nodos que han sido descubiertos, pero no
explorados.
Luego el algoritmo termina de explorar el
nodo inicial, examinando su arista
restante.
Mtl Lourdes Cahuich 19
20. Búsqueda por Niveles
Un nodo está completamente explorado
cuando todas sus aristas han sido
examinadas.
Cuando la exploración de un nodo se
completa, el algoritmo selecciona otro
nodo para ser explorado.
Mtl Lourdes Cahuich 20
21. Búsqueda por Niveles
El algoritmo finalmente termina cuando se
queda sin nodos que requieran ser
explorados.
Mtl Lourdes Cahuich 21
23. void bfs(vector< list<int> >& adj_lists, int start_node) {
queue<int> not_yet_explored;
set<int> discovered;
// Mark the start node as being discovered,
// and place it in the queue of nodes to explore
not_yet_explored.push(start_node);
discovered.insert(start_node);
while (! not_yet_explored.empty()) {
// Get a node to explore.
int node_to_explore = not_yet_explored.front();
not_yet_explored.pop();
// Examine all the edges of the node
list<int>::iterator edges = adj_lists[node_to_explore].begin();
Mtl Lourdes Cahuich 23
24. for ( ; edges != adj_lists[node_to_explore].end(); edges++) {
// See if the edge leads to a node that we
// have not yet discovered
if (discovered.count(*edges) == 0) {
// We have discovered a new node!
// Add this node to the queue of nodes
// to explore.
discovered.insert(*edges);
not_yet_explored.push(*edges);
cout << quot;Found quot; << *edges <<
quot; from quot; << node_to_explore << endl;
}
}
}}
Mtl Lourdes Cahuich 24
25. Búsqueda por Profundidad
Un algoritmo búsqueda por profundidad
(depth-first search) es un algoritmo que
explora los nodos en un grafo, en orden
inverso de la distancia de aumento desde
el nodo inicial.
Mtl Lourdes Cahuich 25
26. Búsqueda por Profundidad
Un algoritmo de búsqueda por
profundidad explora los nodos más
profundos del grafo y luego trabaja de
regreso hacia los nodos que están más
cercanos al nodo inicial
Mtl Lourdes Cahuich 26
27. Búsqueda por Profundidad
Para buscar profundamente en un
laberinto, primero, el algoritmo de
búsqueda por profundidad mantiene un
registro de los nodos a ser explorados en
una pila, en vez de una cola.
Esto causa que los nodos descubiertos
más recientemente sean explorados antes
que los nodos previamente descubiertos.
Mtl Lourdes Cahuich 27
28. Búsqueda por Profundidad
En una búsqueda por niveles, exploramos
los nodos en el orden en que los
descubrimos.
En una búsqueda por profundidad,
exploramos los nodos conforme los vamos
descubriendo
Mtl Lourdes Cahuich 28
31. Implantación - Búsqueda por
Profundidad
La implantación de un algoritmo de
búsqueda por profundidad difiere de la
implantación de uno de búsqueda por
niveles solamente en el contenedor usado
para almacenar los nodos que no han sido
explorados.
Mtl Lourdes Cahuich 31
32. Implantación - Búsqueda por
Profundidad
Un algoritmo de búsqueda por
profundidad siempre explora el nodo
descubierto más recientemente.
Para facilitar esto, los elementos que no
han sido explorados se almacenan en una
pila en vez de una cola
Mtl Lourdes Cahuich 32
33. void dfs_helper(vector<
list<int> >& adj_lists,
set<int>& discovered, int node) {
// Examine all the edges of the node
list<int>::iterator
edges = adj_lists[node].begin();
for ( ; edges !=
adj_lists[node].end();
edges++) {
// See if the edge leads to a node that we
// have not yet discovered
Mtl Lourdes Cahuich 33
34. if (discovered.count(*edges) == 0) {
// We have discovered a new node!
// Add this node to the queue of nodes
// to explore.
discovered.insert(*edges);
cout << quot;Found quot; << *edges <<
quot; from quot; << node << endl;
dfs_helper(adj_lists,
discovered, *edges);
}
}}
Mtl Lourdes Cahuich 34
35. void dfs(vector< list<int> >&
adj_lists, int start_node) {
// Mark the start node as being discovered
set<int> discovered;
discovered.insert(start_node);
dfs_helper(adj_lists,
discovered, start_node);
}
Mtl Lourdes Cahuich 35
36. Cálculo de la Ruta Más Corta
Los cálculos de la ruta más corta son una
familia de algoritmos que determinan la
distancia más corta entre nodos de un
grafo.
Existen diferentes algoritmos de ruta más
corta, debido a que diferentes tipos de
grafos requieren enfoques un poco
diferentes.
Mtl Lourdes Cahuich 36
37. Cálculo de la Ruta Más Corta
En un grafo no ponderado, por ejemplo,
se puede usar simplemente una búsqueda
por niveles para calcular la distancia más
corta entre nodos.
Para grafos ponderados, se deben utilizar
algoritmos diferentes y un poco más
complejos.
Mtl Lourdes Cahuich 37
38. Cálculo de la Ruta Más Corta
Podemos usar el algoritmo Dijkstra si
todos los pesos o valores en un grafo
ponderado son positivos.
Un algoritmo conocido como Bellman-Ford
resuelve el problema de la ruta más corta
para grafos que contienen aristas con
valores negativos
Mtl Lourdes Cahuich 38