estructura de datos - uvamserrano/edi/cap7.pdf · 2006-01-22 · primer vértice es vi; el último...

72
Universidad de Valladolid Departamento de informática Campus de Segovia Estructura de datos Tema 7: Grafos Prof. Montserrat Serrano Montero

Upload: others

Post on 14-Mar-2020

10 views

Category:

Documents


0 download

TRANSCRIPT

Universidad de ValladolidDepartamento de informática

Campus de Segovia

Estructura de datosTema 7: Grafos

Prof. Montserrat Serrano Montero

ÍNDICE

Representación y operaciones• Conceptos básicos• Representaciones• Operaciones del TAD Grafo• Recorridos

CONCEPTOS BÁSICOS• Los grafos permiten representar relaciones

arbitrarias entre datos. No es necesario que exista una jerarquía.

• Los grafos se clasifican en:a) dirigidosb) no dirigidos

• Sus aplicaciones son muy variadas. Se usan para modelar problemas de diversas disciplinas (comunicaciones, ingeniería, biología, etc.)

• En la representación en grafo cada objeto del problema forma un nodo. La relación, comunicación o conexión entre nodos da lugar a una arista, que puede ser bidireccional (no dirigida) o dirigida.

CONCEPTOS BÁSICOS

• Un grafo es un conjunto de vértices o nodos V y un conjunto de arcos A. Se representa con el par G = {V, A}.

• Cuando un nodo v1 apunta a otro nodo v2 se dice que hay un arco o arista (v1, v2) que va del vértice v1 al vértice v2.

• Un grafo se dice que es no dirigido si se cumple la condición de que si (v1, v2) es un arco del grafo, entonces también lo es el arco (v2, v1).

• Para representar un grafo gráficamente, se recurre a dibujar un conjunto de círculos que simbolizan los vértices y un conjunto de segmentos entre ellos que representan los arcos. Si se trata de un arco dirigido los segmentos serán flechas.

CONCEPTOS BÁSICOS

• Un grafo es un conjunto de vértices o nodos V y un conjunto de arcos A. Se representa con el par G = {V, A}.

G1 = {V1, A1} G2 = {V2, A2}• G1 es no dirigido. V1 = {1, 4, 5, 7, 9}

A1 = {(1, 4), (5, 1), (7, 9), (7, 5), (4, 9), (4, 1), (1, 5), (9, 7), (5, 7), (9, 4)}; (v1, v2) ⇒ v1-v2

• G2 es dirigido (digrafo). V2 = {C, D, E, F, H}A2 = {(C, E), (E, D), (F, E), (F, H), (H, F), (D, H)}; (v1, v2) ⇒ v1 → v2

CONCEPTOS BÁSICOSADYACENCIA:• En un grafo no dirigido si la arista (v1, v2)

pertenece al conjunto de las aristas del grafo se dice que los vértices v1 y v2 son adyacentes.

• En un grafo dirigido si el arco (v1, v2) pertenece al conjunto de arcos del grafo, se dice que v1 es adyacente con v2 y v2 es adyacente desde v1. No implica la situación recíproca.

• Un grafo valorado (etiquetado) es aquel que lleva asociado un factor de peso a cada arco o arista. (Ej. peso: los Km. entre ciudades)

CONCEPTOS BÁSICOSGRADO DE UN VÉRTICE:

• Número de arcos o aristas incidentes a dicho vértice.

• En un grafo no dirigido, el grado de un nodo es el número de aristas que contienen a ese nodo.

• En un grafo dirigido podemos considerar:a) Grado de entrada: nº de arcos que llegan a un vértice.b) Grado de salida: nº de arcos que salen de un vértice.c) Vértice aislado: si tiene grado de entrada y salida cero.d) Vértice fuente: tiene grado de entrada cero.e) Vértice sumidero: tiene grado de salida cero.

CONCEPTOS BÁSICOS• Un camino entre dos vértices vi, vj es una

sucesión ordenada de vértices del grafo que cumplen las condiciones siguientes: el primer vértice es vi; el último vértice es vj; cualquier par de vértices consecutivos vp, vq cumplen la condición de que (vp, vq) es un arco del grafo.

• La longitud de un camino es el nº de arcos que lo forma. Si el grafo es valorado, se define la longitud como la suma de los valores de los arcos que lo forman.

• Un camino simple entre dos vértices vi, vj es un camino en el que todos los vértices son distintos excepto el primero y el último si es un ciclo.

• Un ciclo es un camino simple cerrado, compuesto al menos por 3 nodos.

• Un bucle es un camino deun vértice a sí mismo, (v, v).

CONCEPTOS BÁSICOSEjemplos:a)

¿ Qué tipo de camino forman los vértices (A, E, B, F, A) de este grafo?, ¿cuál es su longitud?

b) Idem a) pero para el grafo y los vértices (4, 6, 9, 7):

Solución: a) 4-ciclob) Simple de longitud 3

CONCEPTOS BÁSICOS• Una cadena simple entre dos vértices vi, vj es

una sucesión ordenada de vértices del grafo que cumplen las siguientes condiciones: a) El primer vértice es vi.b) El último vértice es vj.c) Cualquier par de vértices vp, vq cumplen la condición de que o bien (vp, vq) o bien (vq, vp) es un arco del grafo y todos los vértices son distintos excepto posiblemente el primero y el último.

• Subgrafo G’: de un grafo G = {V, A} es un par G’ = (V’, A’) donde V’⊆V y A’ ⊆ A

CONCEPTOS BÁSICOSCONEXIÓN:

• Un grafo dirigido es fuertemente conexo si existe un camino entre cualquier par de nodos que forman el grafo.

• Un grafo dirigido es conexo si existe una cadena que une cualquier par de vértices.

• Un grafo no dirigido G es conexo y fuertemente conexo (se dice conexo) si existe un camino entre cualquier par de nodos que forman el grafo.

• Un grafo completo es aquel que tiene un arco para cualquier par de vértices.

CONCEPTOS BÁSICOSEjemplo:Analizar la conexión y completitud de los siguientes grafos:

Solución: Ninguno es completo.a) Grafo conexob) Grafo fuertemente conexoc) Grafo dirigido conexo

REPRESENTACIÓN DE GRAFOS• Debemos representar un nº finito de vértices

y de arcos que unen dos vértices. Podemos elegir:a) Representación secuencial, mediante arrays: Matriz de adyacencia.b) Representación dinámica, multienlazada: Lista de adyacencia.

• Si G = {V, A} es un grafo de n nodos V = {v1, v2, ..., vn} a los que suponemos ordenados. La representación de los arcos se hace con una matriz A de n x n elementos aijdefinida:

1 si hay un arco (vi, vj)aij

0 si no hay arco (vi, vj)la matriz se denomina matriz de adyacencia. En ocasiones la matriz de adyacencia es una matriz boolean en la que el elemento aij es verdadero si existe arco (vi, vj) y falso en caso contrario.

REPRESENTACIÓN DE GRAFOS• Sea el grafo dirigido siguiente:

Si el orden de los vértices es {D, F, K, L, R}, la matriz de adyacencia será:¿Qué tipo de vértice es K?

REPRESENTACIÓN DE GRAFOS• Sea el grafo no dirigido siguiente:

Si el orden de los vértices es {1, 2, 3, 4, 5}, la matriz de adyacencia será:

Matriz simétrica ya que cada arista (vi, vj) se corresponde con los arcos (vi, vj) y (vj, vi).

REPRESENTACIÓN DE GRAFOS• En el grafo valorado y dirigido siguiente:

Si el orden de los vértices es {Alicante, Barcelona, Cartagena, Murcia, Reus}, la matriz de pesos será:

MATRIZ ADYACENCIADeclaración de tipos:

constmaxvert = 20;

typeindice = 1..maxvert;vertice = string;vertices = array [indice] of vertice;mtAdyace = array [indice, indice] of 0..1;grafo = record

n: indice;v: vertices;A: mtAdyace

end;var G: grafo;

Si el grafo tiene factor de peso numérico, ¿cómo lo podemos declarar?

a) Asociarse directamente a la matriz definiendo un tipo subrango que englobe todos los valores de los pesos. Cambiar 0..1 por ese tipo.

b) Definir un tipo arco como:

type

...

arco = record

adye: boolean;

peso: real

end;

mtAdyace = array [indice, indice] of arco;

OPERACIONES DEL TAD GRAFOPara la matriz de adyacencia:

interfaceprocedure Inicializa (var G: Grafo);function Posicion (G: Grafo, x: string): integer;procedure NuevoArco (var G: Grafo; v1, v2: integer); procedure BorraArco (var G: Grafo; v1, v2: integer); function Adyacente (G: Grafo; v1, v2: integer): boolean; procedure NuevoVert (var G: Grafo, x: string);procedure BorraVert (var G: Grafo, x: string);

implementationprocedure Inicializa;beginG.n := 0

end;

OPERACIONES DEL TAD GRAFOprocedure NuevoArco; begin

G.A[v1, v2] := 1;end;

procedure BorraArco; begin

G.A[v1, v2] := 0;end;

function Adyacente; begin

Adyancente := G.A[v1, v2] = 1;end;

procedure NuevoArco (var G: Grafo; v1, v2: integer; w: real);

beginG.A[v1, v2].adye := true;G.A[v1, v2].peso := w;

end;

OPERACIONES DEL TAD GRAFO

procedure NuevoVert (var G: Grafo; x: string);var i: integer;begin

with G dobeginif n < maxvert then {¿Llenos los arrays?}beginn := n+1; v[n] := x;for i := 1 to n do {Inicializa la matriz de

begin adyacencia con el nuevo vértice}G.A[i, n] := 0;G.A[n, i] := 0

end;end

else writeln (‘Error: no es posible nuevos nodos’);end

end;

OPERACIONES DEL TAD GRAFO

function Posicion (G: Grafo; x: string): integer; {Devuelve la posición de un vértice en el grafo o la

constante –1 si no está}var i, p: integer;beginp := -1; i := 0;while (i < G.n) and (p = -1) do

begini := i +1;if G.v[i] = x then p := i

end;Posicion := p

end;

OPERACIONES DEL TAD GRAFOprocedure BorraVert (var G: Grafo; x: string);var i, p, c: integer;begin

p := Posicion (G, x);with G dobeginif p in [1..G.n] thenbegin{Elimina el vértice x}for i := p to n-1 do v[i] := v[i +1];{Ajuste de matriz de adyacencia}for c := p to n-1 do {Desplaza columnas}for i := 1 to n do A[i, c] := A[i, c+1];

for i := p to n-1 do {Desplaza filas}for c:= 1 to n do A[i, c] := A[i+1, c]

n := n-1;end

else writeln (‘Vértice no existe en el grafo’);end

end;

REPRESENTACIÓN DE GRAFOS

Desventajas de la matriz de adyacencia:• La matriz de adyacencia puede resultar poco

eficiente en los siguientes casos:a) Cuando el número de vértices varíe a lo largo del proceso, sucediendo que sea mayor del previsto.b) Cuando el grafo es disperso, tiene pocos arcos. Esto hace que la matriz tenga muchos ceros y ocupa el mismo espacio que si el grafo tuviera muchos arcos.

• Las listas de adyacencia son una estructura multienlazada formada por una lista directoriocuyos nodos representan los vértices del grafo y de cada nodo también emerge una lista enlazadacuyos nodos representan los arcos con vértice origen el del nodo de la lista directorio.

REPRESENTACIÓN DE GRAFOS• Sea el grafo dirigido siguiente:

La representación de este grafo mediante listas de adyacencia será:

LISTA ADYACENCIADeclaración de tipos:

• Cada nodo de la lista directorio almacena el vértice al que representa, la dirección de acceso a la lista de adyacencia y la dirección del nodo siguiente de la lista directorio.

typetDir = ^NodoDir;tAdy = ^NodoLy;NodoDir = record

vertice: string;plista: tAdy;sig: tDir

end;

LISTA ADYACENCIADeclaración de tipos:

• Cada nodo de la lista de adyacencia de un vértice del grafo almacena la dirección del vértice (en la lista directorio) con el que forma un arco, en caso de ser un grafo valorado también el factor peso, y como en todas las listas la dirección del nodo siguiente.

typeNodoLy = record

pvert: tDir;peso: real;sig: tAdy

end;var G: tDir;

OPERACIONES DEL TAD GRAFOPara la lista de adyacencia:interfaceprocedure Inicializa (var G: tDir);funcion Direccion (G: tDir; x: string): tDir;procedure NuevoArco (var G: tDir; v1, v2: string);procedure BorraArco (var G: tDir; v1, v2: string);function Adyacente (G: tDir; v1, v2:string):boolean;procedure NuevoVert (var G: tDir; x: string);procedure BorraVert (var G: tDir; x: string);

implementationprocedure Inicializa; begin

G := nil; end;

OPERACIONES DEL TAD GRAFOFunciones auxiliares:function CreaVert (x: string): tDir;{Crea un nodo de la lista directorio}var v: tDir;begin

new (v); v^.vertice := x; v^.plista := nil; v^.sig := nil; CreaVert := v

end;procedure NuevoNodoLista (Q: tDir): tAdy; var L: tAdy; {Crea un nodo de una lista enlazadabegin adyacente. No es grafo valorado}

new (L); L^.pvert := Q; L^.sig := nil; NuevoNodoLista := L

end;procedure Anterior (G, P: tDir): tDir; beginwhile G^.sig <> P do G := G^.sig;Anterior := G

end;{Devuelve un puntero al nodo Anterior a una dirección dada en la lista directorio}

Funciones auxiliares:function libera (L: tAdy); {Borra todos losvar aux: tAdy; elementos de una listabegin enlazada adyacente}

while L <> nil dobeginaux := L; L:= L^.sig;dispose (aux)

end;function Ultimo (L: tAdy): tAdy; {Devuelve elbegin ptro. al último nodo de una

if L <> nil then lista enlazada adyacente}while L^.sig <> nil do L := L^.sig

Ultimo := Lend;

function UltimoV (D: tDir): tDir; {Devuelve el begin ptro. al último nodo de laif D <> nil then lista directorio}

while D^.sig <> nil do D := D^.sigUltimoV := D

end;

OPERACIONES DEL TAD GRAFO

OPERACIONES DEL TAD GRAFO

function Direccion (G: tDir; x: string): tDir;var P, D: tDir; {Devuelve un ptro. al nodo en elbegin que se encuentra el vértice pasado comoP := nil; D := G; argumento, dentro de la listawhile (P = nil) and (D <> nil) do directorio}if D^.vertice = x then P:= Delse D := D^.sig;

Direccion := Pend;

procedure NuevoArco (var G: tDir; v1, v2: string);var P, Q: tDir;beginP:= Direccion (G, v1); Q:= Direccion (G, v2);if (P<>nil) and (Q<>nil) thenwith P^ do if plista = nil then plista:= NuevoNodoLista(Q)else Ultimo(plista)^.sig := NuevoNodoLista(Q)

end;{Se añade al final de la lista enlazadaadyacente, si ésta no está vacía}

OPERACIONES DEL TAD GRAFOprocedure BorraArco (var G: tDir; v1,v2: string);var P, D: tDir; R, W: tAdy; Sw: boolean;beginP:= Direccion (G, v1); Q:= Direccion (G, v2);if (P<>nil) and (Q<>nil) thenbeginR:= P^.plista; W:= nil; Sw:= false;while (R <> nil) and not Sw doif R^.pvertice = Q then

begin {Quito 1º elemento de la lista adyac.}if W = nil then P^.plista := R^.sig else W^.sig := R^.sig;{quito otro elemento}dispose (R);Sw := true;

endelse begin

W := R; R:= R^.sigend;

endend; Recorro la lista de adyacencia de v1, buscando el puntero a v2

OPERACIONES DEL TAD GRAFOfunction Adyacente (G: tDir; v1,v2: string):

boolean;var P, Q: tDir; R: tAdy; Sw: boolean;beginP:= Direccion (G, v1); Q:= Direccion (G, v2);if (P< >nil) and (Q< >nil) thenbegin{Proceso de búsqueda}R:= P^.plista; Sw:= false;while (R < > nil) and not Sw do

beginSw := R^.pvertice = Q;if not Sw then R := R^.sig

end;Adyacente := Sw;end {Primer if}

else Adyacente := false; {Si algún vértice no estáend; en la lista directorio}

OPERACIONES DEL TAD GRAFOprocedure NuevoVert (var G: tDir; x: string); begin {El vértice se añade al final si la lista directorio no estáif G <>nil then UltimoV(G)^.sig := CreaVert(x) vacía}else G:= CreaVert (x)

end;procedure BorraVert (var G: tDir; x: string); var P, Q: tDir;begin

P:= Direccion (G, x);if (P <> nil) then

beginQ := G;while Q <> nil dobegin {Borra cualquier nodo donde aparezca x en las

BorraArco (G, Q^.vertice, x); listas enlazadas ady.}Q := Q^.sig

end;{Ahora elimina el nodo de la lista directorio}if G = P then G := G^.sigelse Anterior (G, P)^.sig := P^.sig;libera (P^.plista) {Borra toda la lista enlazada adyacente dispose (P) asociada al vértice}

endend;

REPRESENTACIÓN DE GRAFOSEjercicio:a) Dado el grafo:

Suponiendo la ordenación

Calcular la matriz de adyacencia:

REPRESENTACIÓN DE GRAFOSEjercicio:b) Dado el grafo:Suponiendo la ordenación estándar.

Dibujar la lista de adyacencia:

RECORRIDO DE GRAFOS• La operación de recorrer una estructura consiste

en visitar (procesar) cada uno de los nodos a partir de uno dado.

• Hay dos formas de recorrido:a) Anchurab) Profundidad

• Recorrido en anchura: (2 estructuras auxiliares)a) Una cola donde almacenar los vértices hasta ser procesados.b) Una lista de vértices visitados. Los nodos de esta lista tienen como campos:

- Un puntero al vértice correspondiente de la lista directorio.- Un valor de tipo lógico para marcar si el vértice ha sido visitado.- Un puntero al siguiente elemento se la lista de visitados.

RECORRIDO DE GRAFOSRecorrido en anchura:• Tenemos el grafo:

Se parte del vértice D. Pasos:

1. Se retira el frente de la cola.2. Se meten en la cola los vértices adyacentes al frente no procesados.3. Se vuelve a 1.

RECORRIDO DE GRAFOS• Tipos de datos auxiliares:

typeptrnodoq = ^Nodoq;Nodoq = record

Info: string;Sig: ptrnodoq

end;Cola = record

Frente, Final: ptrnodoqend;ptrlista = ^Nodol;Nodol = record

V: tDir;Vsdo: boolean;Sig : ptrlista

end;

COLA

LISTA VISITADA

RECORRIDO DE GRAFOS• procedimiento Anchura (Grafo,

Puntero al vértice desde el que empieza recorrido)1º.- Procedimiento Lvisitada que crea una lista de punteros con todos los campos visitados a false.2º.- Función Direccion que devuelve un puntero al nodo de la lista visitada donde se encuentra el nodo que apunta al nodo de la lista directorio pasado como argumento.pasos del programa principal:a) Llamar a 1ºb) Inicializar la colac) Meter en la cola el pvértice desde el que empieza el recorrido que se pasa como segundo argumento.d) Bucle hasta que la cola queda vacía:- Saca el frente de la cola que es el pvértice visitado.- Obtiene su lista de adyacencia.- Recorre la lista de adyacencia:1) Se recoge el ptro. a la lista directorio.2) Se llama a 2º para tener la dirección en la lista visitados.3) Se comprueba si esa dirección ha sido visitada:No: se mete en la cola y se pone su campo visitado a true.Sí: se comprueba el siguiente nodo en la lista de adyacencia

procedure Anchura (G, W: tDir);varLv, Av: ptrlista; Q: Cola;N: tDir; L: tAdy;

procedure Lvisitada (var Lv: ptrlista; G: tDir);var P: ptrlista;function CreaV (Q: tDir): ptrlista;var A: ptrlista; beginnew (A); A^.V := Q; A^.Vsdo:= false;CrearV := A

end;begin {Lvisitada}if (G<>nil) then

beginLv:= CreaV(G); P := Lv; G := G^.sig;while (G <> nil) do

beginP^.Sig := CreaV (G);P := P^.Sig; G := G^.sig;

end // end // end; (Sigue)

RECORRIDO DE GRAFOS

{Crea una lista de punteros a los nodos de G con todos los campos visitado igual a false}

function Direccion (L: ptrlista; W: tDir): ptrlista;var {Devuelve un ptro. al nodo de la lista visitadaP, D: ptrlista; donde está el nodo que apunta al

begin nodo de la lista directorio pasado como arg}P:= nil; D:= L;while (P = nil) and (D <> nil) do

if D^.V = W then P:= Delse D := D^.Sig;

Direccion := Pend;begin {Recorrido en Anchura}Lvisitada (Lv, G);Inicia (Q);Encolar (W, Q); Direccion(Lv, W)^.Vsdo := true;repeatDesencolar (W, Q);L := W^.plista;while L<>nil do{Recorre la lista enlazada ady.}beginN := L^.pvert; Av := Direccion (Lv, N);if not Av^.Vsdo then (Sigue)

RECORRIDO DE GRAFOS

RECORRIDO DE GRAFOS

beginEncolar (N, Q);Av^.Vsdo := true

end;L := L^.sig

end;until EsVacia(Q)

end;

• Si se quieren visitar todos los vértices del grafo, una vez terminado el recorrido a partir de uno dado (W) hay que buscar si queda algún vértice sin visitar en cuyo caso se vuelve a recorrer a partir de él, así sucesivamente hasta que todos los vértices estén procesados.

RECORRIDO DE GRAFOSRecorrido en profundidad:• Empieza por un vértice que se marca como

visitado. Después se visita hacia delante hasta que sea posible.

• Las estructuras auxiliares son:a) Una pila donde almacenar los vértices adyacentes no procesados a uno dado. b) Una lista de vértices visitados. Los nodos de esta lista tienen como campos:

- Un puntero al vértice correspondiente de la lista directorio.- Un valor de tipo lógico para marcar si el vértice ha sido visitado.- Un puntero al siguiente elemento de la lista de visitados.

RECORRIDO DE GRAFOSRecorrido en profundidad:• Tenemos el grafo:

Se parte del vértice D. Pasos:

1. Se retira la cima de la pila.2. Se meten en la pila los vértices adyacentes a la cima no procesados.3. Se vuelve a 1.

RECORRIDO DE GRAFOS• Tipos de datos auxiliares:

typeptrnodop = ^Nodop;Nodop = record

Info: string;Sig: ptrnodop

end;ptrlista = ^Nodol;Nodol = record

V: tDir;Vsdo: boolean;Sig : ptrlista

end;

PILA

LISTA VISITADA

RECORRIDO DE GRAFOS• procedimiento Profundidad (Grafo,

Puntero al vértice desde el que empieza recorrido)1º.- Procedimiento Lvisitada que crea una lista de punteros con todos los campos visitados a false.2º.- Función Direccion que devuelve un puntero al nodo de la lista visitada donde se encuentra el nodo que apunta al nodo de la lista directorio pasado como argumento.

pasos del programa principal:a) Llamar a 1ºb) Inicializar la pilac) Meter en la pila el pvértice desde el que empieza el recorrido que se pasa como segundo argumento.d) Bucle hasta que la pila queda vacía:- Desapila la cima obteniendo el pvértice visitado.- Obtiene su lista de adyacencia.- Recorre la lista de adyacencia:1) Se recoge el ptro. a la lista directorio.2) Se llama a 2º para tener la dirección en la lista visitados.3) Se comprueba si esa dirección ha sido visitada:No: se apila y se pone su campo visitado a true.Sí: se comprueba el siguiente nodo en la lista de adyacencia

procedure Profundidad (G, W: tDir);var

Lv, Av: ptrlista; P: ptrnodop;N: tDir; L: tAdy;{Código de procedimientos y funciones auxiliares, igual que el recorrido anchura}

begin Lvisitada (Lv, G);Inicia (P);Apliar (W, P); Direccion (Lv, W)^.Vsdo := true;

repeatDesapilar (W, P); {Vértice W visitado}L := W^.plista;while L<>nil dobegin

N := L^.pvert; Av := Direccion (Lv, N);if not Av^.Vsdo thenbegin

Apilar (N, P);Av^.Vsdo := true

end;L := L^.sig

end;until EsVacia(P)

end;

RECORRIDO DE GRAFOS

RECORRIDO DE GRAFOS

• procedimiento Profundidad (Grafo, Puntero al vértice desde el que empieza recorrido)pasos del programa principal:a) Se pone a true el campo visitado del vértice pasado como argumento.b) Se obtiene la lista de adyacencia del vértice pasado como argumento.c) Bucle hasta que la lista de adyacencia se vacíe:- Caso Base: Que el elemento de la lista de visitados tenga el campo visitado a true- Caso recursivo: Que no se haya visitado el elemento.

RECORRIDO DE GRAFOS

Realización recursiva:procedure Profundidad (W: tDir; var Lv: ptrlista);

var L: tAdy;begin

Direccion (Lv, W)^.Vsdo := true;L := W^.plista;{Lista enlazada ady. del nodo W}while L<>nil do

beginif not Direccion (Lv, L^.pvert)^.Vsdo thenProfundidad (L^.pvert, Lv);

L := L^.sigend

end;

RECORRIDO DE GRAFOS• Ejercicio:

Calcular los recorridos en anchura y profundidad del siguiente grafo desde el vértice A:

¿Qué ocurre si empezamos desde D?

Solución: (desde A)

Anchura: {A, B, D, C, E}

Profundidad: {A, D, E, C, B}

COMPONENTES CONEXAS

• Para comprobar si un grafo no dirigido es conexo, se puede realizar un recorrido en anchura o profundidad, que parta de un vértice cualquiera de él. Al final el grafo será conexo si el conjunto de vértices visitados en el recorrido coincide con todos los vértices del grafo.

• En el caso de grafos dirigidos, se define un grafo G’ que contiene los mismos vértices que G pero todos sus arcos han pasado a ser aristas. Si (v1, v2) está en G, entonces en G’ estarán (v1, v2) y (v2, v1). G es conexo si lo es G’ (no dirigido).

• Si un grafo no es conexo se pueden determinar las componentes conexas que son subgrafos disjuntos del grafo original que son cada uno de ellos conexos.

COMPONENTES CONEXAS

• Algoritmo para determinar las componentes conexas de un grafo G no dirigido:

1. Recorrer el grafo desde cualquier vértice w. Los vértices visitados se guardan en un conjunto W.

2. Si W es el conjunto de todos los vértices del grafo, entonces el grafo es conexo.

3. Si el grafo no es conexo, W es una componente conexa.

4. Se toma un vértice no visitado, z, y se realiza de nuevo el recorrido del grafo a partir de z. Los vértices visitados W forman otra componente conexa.

5. El algoritmo termina cuando todos los vértices han sido visitados.

COMPONENTES CONEXASconst M=100 {Máximo de vértices}type Conjunto = record

Vc: array [1..M] of string;I: 0..M

end;procedure Conexa (G, Z: tDir; var Lv: ptrlista; var

W: Conjunto); var Av: ptrlista; Pila: ptrnodop; N: tDir; L: tAdy;

{Código de procedimientos y funciones auxiliares, igual que recorrido en profundidad}

beginInicia (Pila); Apilar (Z, Pila); Direccion (Lv, Z)^.Vsdo := true; repeatDesapilar (Z, Pila);with W dobeginI := I+1;Vc[I] := Z^.vertice

end;L := Z^.plista; {Lista de adyacencia de Z}

COMPONENTES CONEXASwhile L<> nil dobegin

N := L^.V; Av .= Direccion(Lv,N);if not Av^.Vsdo thenbegin

Apilar(N,Pila);Av^.Vsdo .= true

end;L := L^.sigend

until Esvacia(Pila) end;

procedure Componentes_Conexas(G: Grafo); var T,W: Conjunto; Z: tDir; J, I: integer;function DirNovis (L: ptrlista): ptrlista; var D: ptrlista; Sw: boolean; begin

Sw := false; D := L;while (D<>nil) and not Sw do beginSw := not D^.Vsdo;if not Sw then D := D^.Sgte

end;DirNovis .= D

end;

{Encuentra el nodo de la lista devisitados que no ha sido visitado}

COMPONENTES CONEXASbegin {Componentes_Conexas}{En T guardamos el conjunto de todos los vértices}

with T do beginI := 0; Z:=G;while Z<>nil do beginI:= I +1; Vc [I] := Z^.vertices;Z:= Z^.sig

end;LVisitada (Lv, G); {Todos los vértices a false en campoZ:= DirNovis (Lv); visitado}while Z<>nil dobegin

W.I:= 0;Conexa (G, Z, Lv, W);if W.I = T.I then writeln (‘Grafo conexo’); {Grafo conexo}for J:= 1 to W.I do write (W.Vc [J], ‘ ‘); {Componentewriteln conexa}

end;Z := DirNovis (Lv)

endend;

COMPONENTES FUERTEMENTE CONEXAS

• Un grafo dirigido fuertemente conexo es aquel en el que existe un camino entre cualquier pareja de vértices del grafo.

• De no ser fuertemente conexo se pueden determinar las componentes fuertemente conexas del grafo.

• Algoritmo para determinar las componentes fuertemente conexas de un grafo G dirigido:1. Obtener el conjunto de descendientes de un vértice de partida v, D(v), incluido el propio vértice v. Así, tenemos todos los vértices desde los que hay un camino que comienza en v.

2. Obtener el conjunto de ascendientes de v, A(v), incluido el propio vértice v. Estos vértices son aquellos en los que comienza un camino que llega a v.

3. Los vértices comunes que tienen D y A, es decir D(v) ∩ A(v), es el conjunto de vértices de la componente fuertemente conexa a la que pertenece v. Si este conjunto es igual al conjunto de vértices de G, entonces el grafo es fuertemente conexo.

4. Si no es un grafo fuertemente conexo se selecciona un vértice cualquiera w que no esté en ninguna componente fuerte de las encontradas y se repite todo desde 1 hasta encontrar todas las componentes fuertes del grafo.

COMPO. FUERTEMENTE CONEXAS

Para el paso 2 hay que construir otro grafo Gi que sea resultado de invertir las direcciones de todos los arcos de G y después recorrerlo.

COMPO. FUERTEMENTE CONEXASprogram ComponentesFuertes (input, output);const n = 100;typeVertice = 1..n;tDir = ^NodoDir;tAdy = ^NodoLy;NodoDir = record

Vertice: Vertice; {Identificador del vértice}plista: tAdy;sig: tDirend;

NodoLy = recordpvert: tDir;sig: tAdyend;

Visitados = array [Vertice] of boolean;varG, InvG: tDir;Vstdos, Fuertes, Descendientes, Ascendientes,

Proc, Nulo: Visitados;NumVerts, I, J: integer;

COMPO. FUERTEMENTE CONEXASprocedure ListaDirectorio (var G: tDir; NumVerts:

integer); {Añadir vértices a una lista directoriovar J: integer; vacía}beginG:= nil;for J := 1 to NumVerts doNuevoVert (G, J); {Operación definida en el

end; TAD grafo de listas}procedure Arcos (var G, Gi: tDir; NumVerts:

vertice); {Crea los arcos del grafotype Arco = record dirigido y de su inverso}

x, y: verticeend;

var U: Arco;beginwrite (‘Arcos par ordenado de vértices? (fin eof):');while not eof dobeginread (U.x, U.y); NuevoArco (G, U.x, U.y);NuevoArco (Gi, U.y, U.x);

endend;

COMPO. FUERTEMENTE CONEXASprocedure profundidad (G: tDir; V: Vertice; var Ac:

Visitados);var L: tAdy;begin

Vstdos[V] := true; Ac[V]:=true;while L<>nil dobeginif not Vstdos[L^.pvert^.vertice] then

profundidad (L^.pvert, L^.pvert^.vertice, Ac);L:= L^.sig

end;function Esconexo (Vs: Visitados; Nv: Vertice): boolean;var J: integer; S: boolean;beginS:= true;for J:= 1 to Nv do

S:= S and Vs [J];Esconexo := S

end;procedure Interseccion (D, A: Visitados; Nv: Vertice; var F:

Visitados);var J: Vertice;beginfor J:= 1 to Nv do

F[J]:= F[J] or (D[J] and A[J])end;

COMPO. FUERTEMENTE CONEXASbegin {programa principal}write ('Numero de vertices: '); readln (NumVerts);ListaDirectorio (G, NumVerts); ListaDirectorio (InvG, NumVerts);Arcos (G, InvG, NumVerts);for I:= 1 to NumVerts do Nulo [I]:= false;Fuertes:= Nulo; Proc:=Nulo;for I:= 1 to NumVerts dobeginif not Proc [I] then {Vértice de partida cualquierabegin que no esté en ninguna componente obteni}Vstdos:= Nulo; Descendientes:=Nulo;Ascendientes:= Nulo;profundidad (G, I, Descendientes);Vstdos:= Nulo;profundidad (InvG, I, Ascendientes);Iterseccion (Descendientes, Ascendientes,

NumVerts, Fuertes);

COMPO. FUERTEMENTE CONEXASif Esconexo (Fuertes, NumVerts) thenbeginwriteln ('El grafo es fuertemente conexo');Proc:= Fuertes;

endelse beginwriteln ('Componente fuerte: ');for J:=1 to NumVerts doif Fuertes[J] then write (J, ' ');

writeln;for J:= 1 to NumVerts doProc[J]:= Proc[J] or Fuertes[J];

Fuertes := Nulo; {Prepara para buscar otraend; componente fuerte}

end;G:= G^.sig; InvG:= InvG^.sig;

end {del for}end.

• Ejercicio:Calcular las componentes fuertemente conexas del siguiente grafo:

COMPONENTES FUERTEMENTE CONEXAS

Solución: {F}

{S, C, B}

{M}

MATRIZ DE CAMINOS• Sea G un grafo de n vértices y A su matriz de

adyacencia de tipo lógico. A[i, k] and A[k, j] es cierta si hay un arco del vértice i al k y otro del k al j. También indica que hay un camino de longitud 2 del vértice i al j.

• La expresión:(A[i,1] and A[1, j]) or (A[i, 2] and A[2, j]) or ...or (A[i, NumVerts] and A[NumVerts, j])será cierta si hay al menos 1 camino de longitud 2 desde el vértice i al j que pase a través del vértice 1, o del 2, o del NumVerts.

• Sustituyendo and por * y or por la +, la expresión anterior es la del elemento aij del producto matricial de AxA. Esto supone que los elementos de A2 son true si existe un camino de longitud 2 entre i y j para ∀ i, j =1..n

• En general, para ver si existe un camino de longitud m entre cualquier par de vértices se forma el producto booleano de los caminos de la matriz Am-1 con la matriz de adyacencia A.

MATRIZ DE CAMINOS• Sea G un grafo de n vértices y A su matriz de

adyacencia de tipo lógico:

MATRIZ DE CAMINOS• Sea G un grafo de n vértices y A su matriz de

adyacencia de tipo lógico:

A15 es verdadero ya que hay un camino de longitud 2 desde A-E (A → B → E)

MATRIZ DE CAMINOS• Si en lugar de la matriz con valores lógicos, se

obtiene la matriz con 0 y 1, el valor de calcular las potencias de la matriz de adyacencia representa el número de caminos de longitud k desde el vértice i al j.

procedure Producto_A (A: MatAdcia; k: integer; Nvs: Vertice; var Ak: MatAdcia);

varI: integer;

procedure Prod (A, B: MatAdcia; var N: MatAdcia);

var f, c, k, s: integer;beginfor f := 1 to Nvs dofor c:= 1 to Nvs dobegins:= 0;for k:= 1 to Nvs dos := s + A[f, k] * B[c, k];

N [f, c] := s end

end;begin {Producto}Ak := A;for I := 2 to k do Prod (Ak, A, Ak)

end;

NÚMERO DE CAMINOS

MATRIZ DE CAMINOS• Sea G un grafo de n vértices. La matriz de

caminos de G es una matriz nxn definida: pijvale 1 si hay un camino de vi a vj y cero en caso contrario.

• El camino de vi a vj será:a) Simple si vi<>vj con longitud n-1 o menor.b) Ciclo si vi = vj con longitud n o menor.

• Dada la matriz Bn = A + A2 + A3 + ...+ An, la matriz de caminos P = (Pij) es tal que un elemento Pij =1 ⇔ Bn(i,j) = 1 y en otro caso Pij= 0.

• Otra forma de determinar que un grafo es fuertemente conexo consiste en ver si su matriz de caminos tiene todos los elementos a 1.

MATRIZ DE CAMINOS• Cierre transitivo:

De un grafo G es otro G’ que tiene los mismos vértices y que tiene como matriz de adyacencia la matriz de caminos P del grafo G. Según esta definición un grafo es fuertemente conexo ⇔ su cierre transitivo es un grafo completo.

• Ejercicio:a) ¿Cuál es la matriz de caminos del siguiente grafo?

b) ¿es fuertemente conexo?

PUNTOS DE ARTICULACIÓN• Un punto de articulación de un grafo no

dirigido es un vértice V que si se elimina junto a sus arcos, hace que la componente conexa en que está el vértice se divide en dos o más componentes.

Encontrar sus puntos de articulación.

PUNTOS DE ARTICULACIÓN

• Un grafo biconexo no tiene puntos de articulación.

• Un grafo tiene conectividad k si la eliminación de k-1 vértices cualesquiera del grafo no lo divide en componentes conexas (no lo desconecta).

• Cuanto mayor sea la conectividad de un grafo (una red por ejemplo), tanta mayor probabilidad tendrá de mantener la estructura ante el fallo (eliminación) de alguno de sus vértices.