Menu iconMenu icon
Algoritmos y Estructuras de Datos con Python

Capítulo 8: Redes y Caminos: Algoritmos Avanzados de Grafos

Ejercicios Prácticos para el Capítulo 8

Estos ejercicios están diseñados para mejorar la comprensión de algoritmos de grafos avanzados, brindando experiencia práctica en la aplicación de estas técnicas para resolver problemas complejos.

Ejercicio 1: Implementación del Algoritmo de Dijkstra

  • Escriba una función para realizar el algoritmo de Dijkstra para encontrar el camino más corto desde una única fuente hasta todos los demás nodos en un grafo ponderado.
  • Grafo de ejemplo: { 'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {} }, y nodo de inicio: 'A'.

Solución:

import heapq

def dijkstra(graph, start):
    distances = {vertex: float('infinity') for vertex in graph}
    distances[start] = 0
    pq = [(0, start)]

    while pq:
        current_distance, current_vertex = heapq.heappop(pq)

        for neighbor, weight in graph[current_vertex].items():
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, neighbor))

    return distances

# Example Usage
graph = {'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {}}
print(dijkstra(graph, 'A'))  # Output: {'A': 0, 'B': 1, 'C': 3, 'D': 4}

Ejercicio 2: Encontrar Puentes en un Grafo

  • Implementar un algoritmo para encontrar todos los puentes en un grafo no dirigido.
  • Grafo de ejemplo: Usa el grafo del Ejercicio 1.

Solución:

from collections import defaultdict

class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = defaultdict(list)
        self.time = 0

    def add_edge(self, u, v):
        self.graph[u].append(v)
        self.graph[v].append(u)

    def bridge_util(self, u, visited, low, disc, parent, bridges):
        visited[u] = True
        disc[u] = self.time
        low[u] = self.time
        self.time += 1

        for v in self.graph[u]:
            if not visited[v]:
                parent[v] = u
                self.bridge_util(v, visited, low, disc, parent, bridges)
                low[u] = min(low[u], low[v])

                if low[v] > disc[u]:
                    bridges.append((u, v))
            elif v != parent[u]:
                low[u] = min(low[u], disc[v])

    def find_bridges(self):
        visited = [False] * self.V
        disc = [float("Inf")] * self.V
        low = [float("Inf")] * self.V
        parent = [-1] * self.V
        bridges = []

        for i in range(self.V):
            if not visited[i]:
                self.bridge_util(i, visited, low, disc, parent, bridges)
        return bridges

# Example Usage
g = Graph(4)
g.add_edge(0, 1)
g.add_edge(1, 2)
g.add_edge(2, 3)
print(g.find_bridges())  # Output: [(2, 3)]

Ejercicio 3: Implementación del Algoritmo de Floyd-Warshall

  • Crear una función para encontrar las distancias más cortas entre cada par de vértices en un grafo ponderado dado.
  • Grafo de ejemplo: Usa el grafo del Ejercicio 1.

Solución:

def floyd_warshall(graph):
    keys = list(graph.keys())
    n = len(keys)
    dist = {k: {k2: float('inf') for k2 in keys} for k in keys}
    for key in keys:
        dist[key][key] = 0
    for key, val in graph.items():
        for adj, weight in val.items():
            dist[key][adj] = weight

    for k in keys:
        for i in keys:
            for j in keys:
                if dist[i][j] > dist[i][k] + dist[k][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]

    return dist

# Example Usage
graph = {'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {}}
print(floyd_warshall(graph))

Ejercicios Prácticos para el Capítulo 8

Estos ejercicios están diseñados para mejorar la comprensión de algoritmos de grafos avanzados, brindando experiencia práctica en la aplicación de estas técnicas para resolver problemas complejos.

Ejercicio 1: Implementación del Algoritmo de Dijkstra

  • Escriba una función para realizar el algoritmo de Dijkstra para encontrar el camino más corto desde una única fuente hasta todos los demás nodos en un grafo ponderado.
  • Grafo de ejemplo: { 'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {} }, y nodo de inicio: 'A'.

Solución:

import heapq

def dijkstra(graph, start):
    distances = {vertex: float('infinity') for vertex in graph}
    distances[start] = 0
    pq = [(0, start)]

    while pq:
        current_distance, current_vertex = heapq.heappop(pq)

        for neighbor, weight in graph[current_vertex].items():
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, neighbor))

    return distances

# Example Usage
graph = {'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {}}
print(dijkstra(graph, 'A'))  # Output: {'A': 0, 'B': 1, 'C': 3, 'D': 4}

Ejercicio 2: Encontrar Puentes en un Grafo

  • Implementar un algoritmo para encontrar todos los puentes en un grafo no dirigido.
  • Grafo de ejemplo: Usa el grafo del Ejercicio 1.

Solución:

from collections import defaultdict

class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = defaultdict(list)
        self.time = 0

    def add_edge(self, u, v):
        self.graph[u].append(v)
        self.graph[v].append(u)

    def bridge_util(self, u, visited, low, disc, parent, bridges):
        visited[u] = True
        disc[u] = self.time
        low[u] = self.time
        self.time += 1

        for v in self.graph[u]:
            if not visited[v]:
                parent[v] = u
                self.bridge_util(v, visited, low, disc, parent, bridges)
                low[u] = min(low[u], low[v])

                if low[v] > disc[u]:
                    bridges.append((u, v))
            elif v != parent[u]:
                low[u] = min(low[u], disc[v])

    def find_bridges(self):
        visited = [False] * self.V
        disc = [float("Inf")] * self.V
        low = [float("Inf")] * self.V
        parent = [-1] * self.V
        bridges = []

        for i in range(self.V):
            if not visited[i]:
                self.bridge_util(i, visited, low, disc, parent, bridges)
        return bridges

# Example Usage
g = Graph(4)
g.add_edge(0, 1)
g.add_edge(1, 2)
g.add_edge(2, 3)
print(g.find_bridges())  # Output: [(2, 3)]

Ejercicio 3: Implementación del Algoritmo de Floyd-Warshall

  • Crear una función para encontrar las distancias más cortas entre cada par de vértices en un grafo ponderado dado.
  • Grafo de ejemplo: Usa el grafo del Ejercicio 1.

Solución:

def floyd_warshall(graph):
    keys = list(graph.keys())
    n = len(keys)
    dist = {k: {k2: float('inf') for k2 in keys} for k in keys}
    for key in keys:
        dist[key][key] = 0
    for key, val in graph.items():
        for adj, weight in val.items():
            dist[key][adj] = weight

    for k in keys:
        for i in keys:
            for j in keys:
                if dist[i][j] > dist[i][k] + dist[k][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]

    return dist

# Example Usage
graph = {'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {}}
print(floyd_warshall(graph))

Ejercicios Prácticos para el Capítulo 8

Estos ejercicios están diseñados para mejorar la comprensión de algoritmos de grafos avanzados, brindando experiencia práctica en la aplicación de estas técnicas para resolver problemas complejos.

Ejercicio 1: Implementación del Algoritmo de Dijkstra

  • Escriba una función para realizar el algoritmo de Dijkstra para encontrar el camino más corto desde una única fuente hasta todos los demás nodos en un grafo ponderado.
  • Grafo de ejemplo: { 'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {} }, y nodo de inicio: 'A'.

Solución:

import heapq

def dijkstra(graph, start):
    distances = {vertex: float('infinity') for vertex in graph}
    distances[start] = 0
    pq = [(0, start)]

    while pq:
        current_distance, current_vertex = heapq.heappop(pq)

        for neighbor, weight in graph[current_vertex].items():
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, neighbor))

    return distances

# Example Usage
graph = {'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {}}
print(dijkstra(graph, 'A'))  # Output: {'A': 0, 'B': 1, 'C': 3, 'D': 4}

Ejercicio 2: Encontrar Puentes en un Grafo

  • Implementar un algoritmo para encontrar todos los puentes en un grafo no dirigido.
  • Grafo de ejemplo: Usa el grafo del Ejercicio 1.

Solución:

from collections import defaultdict

class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = defaultdict(list)
        self.time = 0

    def add_edge(self, u, v):
        self.graph[u].append(v)
        self.graph[v].append(u)

    def bridge_util(self, u, visited, low, disc, parent, bridges):
        visited[u] = True
        disc[u] = self.time
        low[u] = self.time
        self.time += 1

        for v in self.graph[u]:
            if not visited[v]:
                parent[v] = u
                self.bridge_util(v, visited, low, disc, parent, bridges)
                low[u] = min(low[u], low[v])

                if low[v] > disc[u]:
                    bridges.append((u, v))
            elif v != parent[u]:
                low[u] = min(low[u], disc[v])

    def find_bridges(self):
        visited = [False] * self.V
        disc = [float("Inf")] * self.V
        low = [float("Inf")] * self.V
        parent = [-1] * self.V
        bridges = []

        for i in range(self.V):
            if not visited[i]:
                self.bridge_util(i, visited, low, disc, parent, bridges)
        return bridges

# Example Usage
g = Graph(4)
g.add_edge(0, 1)
g.add_edge(1, 2)
g.add_edge(2, 3)
print(g.find_bridges())  # Output: [(2, 3)]

Ejercicio 3: Implementación del Algoritmo de Floyd-Warshall

  • Crear una función para encontrar las distancias más cortas entre cada par de vértices en un grafo ponderado dado.
  • Grafo de ejemplo: Usa el grafo del Ejercicio 1.

Solución:

def floyd_warshall(graph):
    keys = list(graph.keys())
    n = len(keys)
    dist = {k: {k2: float('inf') for k2 in keys} for k in keys}
    for key in keys:
        dist[key][key] = 0
    for key, val in graph.items():
        for adj, weight in val.items():
            dist[key][adj] = weight

    for k in keys:
        for i in keys:
            for j in keys:
                if dist[i][j] > dist[i][k] + dist[k][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]

    return dist

# Example Usage
graph = {'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {}}
print(floyd_warshall(graph))

Ejercicios Prácticos para el Capítulo 8

Estos ejercicios están diseñados para mejorar la comprensión de algoritmos de grafos avanzados, brindando experiencia práctica en la aplicación de estas técnicas para resolver problemas complejos.

Ejercicio 1: Implementación del Algoritmo de Dijkstra

  • Escriba una función para realizar el algoritmo de Dijkstra para encontrar el camino más corto desde una única fuente hasta todos los demás nodos en un grafo ponderado.
  • Grafo de ejemplo: { 'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {} }, y nodo de inicio: 'A'.

Solución:

import heapq

def dijkstra(graph, start):
    distances = {vertex: float('infinity') for vertex in graph}
    distances[start] = 0
    pq = [(0, start)]

    while pq:
        current_distance, current_vertex = heapq.heappop(pq)

        for neighbor, weight in graph[current_vertex].items():
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, neighbor))

    return distances

# Example Usage
graph = {'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {}}
print(dijkstra(graph, 'A'))  # Output: {'A': 0, 'B': 1, 'C': 3, 'D': 4}

Ejercicio 2: Encontrar Puentes en un Grafo

  • Implementar un algoritmo para encontrar todos los puentes en un grafo no dirigido.
  • Grafo de ejemplo: Usa el grafo del Ejercicio 1.

Solución:

from collections import defaultdict

class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = defaultdict(list)
        self.time = 0

    def add_edge(self, u, v):
        self.graph[u].append(v)
        self.graph[v].append(u)

    def bridge_util(self, u, visited, low, disc, parent, bridges):
        visited[u] = True
        disc[u] = self.time
        low[u] = self.time
        self.time += 1

        for v in self.graph[u]:
            if not visited[v]:
                parent[v] = u
                self.bridge_util(v, visited, low, disc, parent, bridges)
                low[u] = min(low[u], low[v])

                if low[v] > disc[u]:
                    bridges.append((u, v))
            elif v != parent[u]:
                low[u] = min(low[u], disc[v])

    def find_bridges(self):
        visited = [False] * self.V
        disc = [float("Inf")] * self.V
        low = [float("Inf")] * self.V
        parent = [-1] * self.V
        bridges = []

        for i in range(self.V):
            if not visited[i]:
                self.bridge_util(i, visited, low, disc, parent, bridges)
        return bridges

# Example Usage
g = Graph(4)
g.add_edge(0, 1)
g.add_edge(1, 2)
g.add_edge(2, 3)
print(g.find_bridges())  # Output: [(2, 3)]

Ejercicio 3: Implementación del Algoritmo de Floyd-Warshall

  • Crear una función para encontrar las distancias más cortas entre cada par de vértices en un grafo ponderado dado.
  • Grafo de ejemplo: Usa el grafo del Ejercicio 1.

Solución:

def floyd_warshall(graph):
    keys = list(graph.keys())
    n = len(keys)
    dist = {k: {k2: float('inf') for k2 in keys} for k in keys}
    for key in keys:
        dist[key][key] = 0
    for key, val in graph.items():
        for adj, weight in val.items():
            dist[key][adj] = weight

    for k in keys:
        for i in keys:
            for j in keys:
                if dist[i][j] > dist[i][k] + dist[k][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]

    return dist

# Example Usage
graph = {'A': {'B': 1, 'C': 4}, 'B': {'C': 2, 'D': 5}, 'C': {'D': 1}, 'D': {}}
print(floyd_warshall(graph))