import numpy as gr # Usamos gr como alias para numpy
import sys
class Grafo:
def __init__(self):
#constriumos el objeto grafo, inicializamos en una matriz de 8 x 8 con ceros.
#definimos los nodos desde la A hasta la H
fila = 8
columna = 8
self.Matriz = gr.zeros((fila,columna), dtype=int)
self.nodos = ['A','B','C','D','E','F','G','H']
def agregar_peso (self, nodo1, nodo2, peso):
#Convierto las letras a indice
index1 = self.nodos.index(nodo1)
index2 = self.nodos.index(nodo2)
#Agrego el peso a la matriz
self.Matriz[index1][index2]= peso
def mostrar_matriz___(self):
print("Matriz de adyacencia:")
print(" " + " ".join(self.nodos)) # con .join uno los elementos en una sola cadena
for i, fila in enumerate(self.Matriz): #enumerate se utiliza para obtener tanto el índice (i) como el contenido de cada fila (fila)
print(self.nodos[i], " ".join(map(str, fila)))
def agregar_nodo(self, nuevo_nodo):
if nuevo_nodo not in self.nodos: # verifico que el nodo no este
self.nodos.append(nuevo_nodo)
# Ampliar la matriz para incluir el nuevo nodo
nueva_matriz = gr.zeros((len(self.nodos), len(self.nodos)), dtype=int) # genero una nueva matriz con los tamaños que tengo
nueva_matriz[:self.Matriz.shape[0], :self.Matriz.shape[1]] = self.Matriz # copio los valores de filas y columna de la matriz
self.Matriz = nueva_matriz
print(f"Nodo {nuevo_nodo} agregado.")
else:
print("El nodo ya existe.")
def agregar_arista(self, nodo1, nodo2, peso):
if nodo1 in self.nodos and nodo2 in self.nodos: # busco los nodos y condiciono para que existan
self.agregar_peso(nodo1, nodo2, peso)
print(f"Arista agregada de {nodo1} a {nodo2} con peso {peso}.")
else:
print("Uno o ambos nodos no existen.")
def ingresar_valores(self):
print("Por favor, ingresa 8 valores para la matriz:")
#solicito los valores de los tramos
while True:
#capturo errores de ingreso
try:
peso_AB = int(input ("Ingrese el recorrido A-B: "))
peso_AC = int(input ("Ingrese el recorrido A-C: "))
peso_BD = int(input ("Ingrese el recorrido B-D: "))
peso_BG = int(input ("Ingrese el recorrido B-G: "))
peso_CD = int(input ("Ingrese el recorrido C-D: "))
peso_CF = int(input ("Ingrese el recorrido C-F: "))
peso_DE = int(input ("Ingrese el recorrido D-E: "))
peso_DF = int(input ("Ingrese el recorrido D-F: "))
peso_EG = int(input ("Ingrese el recorrido E-G: "))
peso_EH = int(input ("Ingrese el recorrido E-H: "))
peso_FH = int(input ("Ingrese el recorrido F-H: "))
# condiciono para que los valores ingresados sean positivos
if peso_AB <= 0 or peso_AC <= 0 or peso_BD <= 0 or peso_BG <= 0 or peso_CD <= 0 or peso_CF <= 0 or peso_DE <= 0 or peso_DF <= 0 or peso_EG <= 0 or peso_FH <= 0 or peso_EH <= 0:
print("Los núemros de los recorridos deben ser positivos , ((((()))))")
print("--------- Intente otra vez ------" )
break
else:
self.agregar_peso('A', 'B', peso_AB)
self.agregar_peso('A', 'C', peso_AC)
self.agregar_peso('B', 'D', peso_BD)
self.agregar_peso('B', 'G', peso_BG)
self.agregar_peso('C', 'D', peso_CD)
self.agregar_peso('C', 'F', peso_CF)
self.agregar_peso('D', 'F', peso_DF)
self.agregar_peso('D', 'E', peso_DE)
self.agregar_peso('E', 'G', peso_EG)
self.agregar_peso('E', 'H', peso_EH)
self.agregar_peso('F', 'H', peso_FH)
break
except ValueError:
print("Por favor, ingresa un número entero válido.")
def dijkstra (self, inicio, fin):
num_nodos = len(self.nodos)
distancias = [float('inf')] * num_nodos
distancias[self.nodos.index(inicio)] = 0
visitados = [False] * num_nodos
predecesores = [None] * num_nodos
for _ in range(num_nodos): # el _ significa que no es necesario un valor sino que se usa para recorrer el bucle
nodo_actual = min((i for i in range(num_nodos) if not visitados[i]), #Este es un generador que itera sobre todos los índices de los nodos (de 0 a num_nodos - 1).
key=lambda i: distancias[i], default=None) #if not visitados[i] filtra solo los nodos que no han sido visitados.
#Así, solo se consideran aquellos nodos que aún no han sido procesados por el algoritmo.
if nodo_actual is None or distancias[nodo_actual] == float('inf'):
break
visitados[nodo_actual] = True
for vecino in range(num_nodos):
peso_arista = self.Matriz[nodo_actual][vecino]
if peso_arista > 0:
nueva_distancia = distancias[nodo_actual] + peso_arista
if nueva_distancia < distancias[vecino]:
distancias[vecino] = nueva_distancia
predecesores[vecino] = nodo_actual
camino = []
nodo = self.nodos.index(fin)
while nodo is not None:
camino.append(self.nodos[nodo])
nodo = predecesores[nodo]
camino.reverse()
return camino, distancias[self.nodos.index(fin)]
grafo = Grafo() # creo una instancia del objeto
print(grafo.mostrar_matriz___())
grafo.ingresar_valores()
print(grafo.mostrar_matriz___())
# Agregar un nuevo nodo
#grafo.agregar_nodo('I')
# Agregar una nueva arista
#grafo.agregar_arista('A', 'I', 5)
# Mostrar la matriz actualizada
#print(grafo.mostrar_matriz___())
# Solicitar al usuario el nodo de inicio
inicio = input("Ingresa el nodo de inicio (A-H): ").strip().upper()
if inicio in grafo.nodos:
camino, distancia = grafo.dijkstra(inicio, 'H')
print(f"El camino más corto de {inicio} a H es: {' -> '.join(camino)} con una distancia de {distancia}.")
else:
print("Nodo de inicio inválido. Debe ser entre A y H.")