Sunteți pe pagina 1din 7

Algoritmos de grafos

Los problemas de grafos son muy frecuentes en los concursos de programación.


Para resolver un problema de grafos, la dificultad no es tanto implementar el
algoritmo, sino identificar correctamente el tipo de problema de qué se trata. Los
algoritmos no se necesitan memorizar, sino que se pueden llevar en forma de
código al concurso (véase el "notebook").

Sin embargo, en esta clase vamos a ver un par de ejemplos de cómo implementar
los algoritmos de grafos. Antes que nada, es muy común nombrar los nodos del
grafo 0,...,N, ya que podemos usar el nombre de cada nodo como índice en un
vector o una matriz.

Representaciones de grafos

Hay tres maneras comunes para representar los grafos; vamos a tomar el
siguiente grafo como ejemplo:

1. Matriz de adyacencia: las aristas del grafo se guardan en una matriz,


indicando si un nodo tiene enlace directo con otro.

O\D 0 1 2 3 4 5
0 010100
1 001010
2 000010
3 010000
4 000101
5 001000

2.
En C++, podemos usar un doble array para guardar la matriz de antes:
3.
4. int A[6][6];
5. //inicializar todo a 0
6. for(int i=0;i<6;i++)
7. for(int j=0;j<6;j++)
8. A[i][j] = 0;
9. //1 si hay enlace origen -> destino
10. A[0][1] = 1;
11. A[1][2] = 1;
12. A[1][4] = 1;
13. A[2][4] = 1;
14. A[3][1] = 1;
15. A[4][3] = 1;
16. A[4][5] = 1;
17. A[5][2] = 1;

2. Lista de adyacencia: para cada nodo, sólo se guardan sus vecinos.

0 -> 1 3
1 -> 2 4
2 -> 4
3 -> 1
4 -> 3 5
5 -> 2

En C++, podemos usar un vector de vectores para guardar la lista anterior:


18.
19. vector<vector<int> > A(6);
20. //para cada posición origen añadir vecino
21. A[0].push_back(1);
22. A[0].push_back(3);
23. A[1].push_back(2);
24. A[1].push_back(4);
25. A[2].push_back(4);
26. A[3].push_back(1);
27. A[4].push_back(3);
28. A[4].push_back(5);
29. A[5].push_back(2);

3. Lista de aristas: se guarda una lista de todas las aristas del grafo.

(0,1) (0,3) (1,2) (1,4) (2,4) (3,1) (4,3) (4,5) (5,2)

En C++, podemos usar un vector de pares de enteros para guardar la lista:


30.
31. //librería para utilizar pair
32. #include <utility>;
33. //vector de aristas
34. vector<pair<int,int> > A;
35. //insertamos las aristas en el vector
36. A.push_back(make_pair(0, 1));
37. A.push_back(make_pair(0, 3));
38. A.push_back(make_pair(1, 2));
39. A.push_back(make_pair(1, 4));
40. A.push_back(make_pair(2, 4));
41. A.push_back(make_pair(3, 1));
42. A.push_back(make_pair(4, 3));
43. A.push_back(make_pair(4, 5));
44. A.push_back(make_pair(5, 2));

Para grafos con costes, en la matriz de adyacencia simplemente se puede guardar


el coste de cada arista. La lista de adyacencia tiene que incluir 2 valores para
cada arista: el vecino y el coste, lo que se puede representar con pares de enteros.
La lista de aristas tiene que incluir 3 valores para cada arista: los dos nodos y el
coste. Se puede representar por un struct o combinando pares.

http://www.dtic.upf.edu/~jonsson/acm/grafos/

Definición
Un grafo es un objeto matemático que se utiliza para representar circuitos, redes, etc.
Los grafos son muy utilizados en computación, ya que permiten resolver problemas
muy complejos.

Imaginemos que disponemos de una serie de ciudades y de carreteras que las unen.
De cada ciudad saldrán varias carreteras, por lo que para ir de una ciudad a otra se
podrán tomar diversos caminos. Cada carretera tendrá un coste asociado (por ejemplo,
la longitud de la misma). Gracias a la representación por grafos podremos elegir el
camino más corto que conecta dos ciudades, determinar si es posible llegar de una
ciudad a otra, si desde cualquier ciudad existe un camino que llegue a cualquier otra,
etc.

El estudio de grafos es una rama de la algoritmia muy importante. Estudiaremos


primero sus rasgos generales y sus recorridos fundamentales, para tener una buena
base que permita comprender los algoritmos que se pueden aplicar.

Un grafo consta de vértices (o nodos) y aristas. Los vértices son objetos que contienen
información y las aristas son conexiones entre vértices. Para representarlos, se suelen
utilizar puntos para los vértices y líneas para las conexiones, aunque hay que recordar
siempre que la definición de un grafo no depende de su representación.

Un camino entre dos vértices es una lista de vértices en la que dos elementos
sucesivos están conectados por una arista del grafo. Así, el camino AJLOE es un
camino que comienza en el vértice A y pasa por los vértices J,L y O (en ese orden) y al
final va del O al E. El grafo será conexo si existe un camino desde cualquier nodo del
grafo hasta cualquier otro. Si no es conexo constará de varias componentes conexas.
Un camino simple es un camino desde un nodo a otro en el que ningún nodo se repite
(no se pasa dos veces). Si el camino simple tiene como primer y último elemento al
mismo nodo se denomina ciclo. Cuando el grafo no tiene ciclos tenemos
un árbol (ver árboles). Varios árboles independientes forman un bosque. Un árbol de
expansión de un grafo es una reducción del grafo en el que solo entran a formar parte
el número mínimo de aristas que forman un árbol y conectan a todos los nodos.

Según el número de aristas que contiene, un grafo es completo si cuenta con todas las
aristas posibles (es decir, todos los nodos están conectados con todos), disperso si
tiene relativamente pocas aristas y denso si le faltan pocas para ser completo.

Las aristas son la mayor parte de las veces bidireccionales, es decir, si una arista
conecta dos nodos A y B se puede recorrer tanto en sentido hacia B como en sentido
hacia A: estos son llamados grafos no dirigidos. Sin embargo, en ocasiones tenemos
que las uniones son unidireccionales. Estas uniones se suelen dibujar con una flecha y
definen un grafo dirigido. Cuando las aristas llevan un coste asociado (un entero al que
se denomina peso) el grafo es ponderado. Una red es un grafo dirigido y ponderado.

Exploración de grafos
A la hora de explorar un grafo, nos encontramos con dos métodos distintos. Ambos
conducen al mismo destino (la exploración de todos los vértices o hasta que se
encuentra uno determinado), si bien el orden en que éstos son "visitados" decide
radicalmente el tiempo de ejecución de un algoritmo, como se verá posteriormente.

En primer lugar, una forma sencilla de recorrer los vértices es mediante una función
recursiva, lo que se denomina búsqueda en profundidad. La sustitución de la recursión
(cuya base es la estructura de datos pila) por una cola nos proporciona el segundo
método de búsqueda o recorrido, la búsqueda en amplitud o anchura.

Suponiendo que el orden en que están almacenados los nodos en la estructura de


datos correspondiente es A-B-C-D-E-F... (el orden alfabético), tenemos que el orden
que seguiría el recorrido en profundidad sería el siguiente:

A-B-E-I-F-C-G-J-K-H-D
En un recorrido en anchura el orden sería, por contra:

A-B-C-D-E-G-H-I-J-K-F

Es decir, en el primer caso se exploran primero los verdes y luego los marrones,
pasando primero por los de mayor intensidad de color. En el segundo caso se exploran
primero los verdes, después los rojos, los naranjas y, por último, el rosa.

Es destacable que el nodo D es el último en explorarse en la búsqueda en profundidad


pese a ser adyacente al nodo de origen (el A). Esto es debido a que primero se explora
la rama del nodo C, que también conduce al nodo D.

En estos ejemplos hay que tener en cuenta que es fundamental el orden en que los
nodos están almacenados en las estructuras de datos. Si, por ejemplo, el nodo D
estuviera antes que el C, en la búsqueda en profundidad se tomaría primero la rama
del D (con lo que el último en visitarse sería el C), y en la búsqueda en anchura se
exploraría antes el H que el G.

http://www.algoritmia.net/articles.php?id=18

Clasificación de los grafos

Grafos dirigidos y no dirigidos dependiendo del tipo de relación entre los vértices del grafo,
se definen distintos tipos de grafos. Así se distinguen aristas dirigidas y no dirigidas:

Arista dirigida: es aquella que define un par ordenado de vértices (a,b), donde el primer
vértice u es el origen de la arista y el segundo vértice v es el término (o vértice final). El par
(a, b) ≠ (a, b).

Arista no dirigida: es aquella que define un par no ordenado de vértices (a, b), donde (a, b)
= (a, b).
Grafo dirigido
Es aquel cuyas aristas son no dirigidas. Representan relaciones simétricas como relaciones de
hermandad y colaboración, conexiones de transportes, etc.

Cada arco esta representado por un par ordenado de vertices, de forma que representan dos
arcos diferentes.

En grafos dirigidos se impone un sentido a los enlaces. Cada arista del grafo dirigido incluye
una flecha para indicar la dirección.

Grafo no dirigido
Es aquel cuyas aristas son dirigidas. Los grafos dirigidos suelen representar relaciones
asimétricas como por ejemplo: relaciones de herencia, los vuelos entre ciudades, etc.

Los arcos en el grafo no tienen una dirección particular, es decir, son bidireccionales(pueden
ser considerados un caso particular de los anteriores).
Grafo mixto

Es aquel que se define con la capacidad de poder contener aristas dirigidas y no dirigidas.
Tanto los grafos dirigidos como los no dirigidos son casos particulares de este.

http://tudefinicion.blogspot.mx/2015/01/clasificacion-de-los-grafos-los-grafos.html

S-ar putea să vă placă și