""" ============================================================================= Sección Declarativa - Programa Principal Descripción: Calcula y muestra la sucesión alícuota de un entero n >= 2 hasta llegar a 1 o detectar un ciclo (período 1 o 2). Casos de prueba: - 10 → 8 → 7 → 1 (Terminación en 1) - 6 → 6 (Ciclo perfecto - período 1) - 220 → 284 → 220 (Ciclo números amigos - período 2) - 95 → 25 → 6 → 6 (Ciclo perfecto - período 1) - 12496 → 14288 → 15472 → 14536 → 14264 → 12496 (Ciclo números amigos - período 5) - 14316 → ... (Ciclo números amigos - período 28) - 276 → ... (Se alcanza el límite de términos sin detectar si termina en 1 o hay ciclo) Recursos del programa principal: - valor_inicial (int): Número base de la sucesión ingresado por el usuario. ============================================================================= """ # ========================================== # DEFINICIÓN DE FUNCIONES # ========================================== def suma_alicuota(n): """ Sección Declarativa Descripción: Retorna la suma de los divisores propios de n (s(n)). Nota: Se reutiliza la lógica algorítmica de suma_divisores_propios. """ suma_divisores = 1 # todo número es divisible por la unidad y no se requiere verificarlo ultimo = int(n ** 0.5) # Bucle que evalúa cada número desde 2 hasta ultimo-1 para hallar divisores exactos. for d in range(2, ultimo): if n % d == 0: suma_divisores += d + n // d # Verificación de ultimo if n % ultimo == 0: # ultimo es divisor suma_divisores += ultimo otro = n // ultimo if otro != ultimo: # n no es un cuadrado suma_divisores += otro return suma_divisores def mostrar_sucesion_alicuota(n): """ Sección Declarativa Descripción: Genera iterativamente la sucesión alícuota manejando el seguimiento de términos anteriores para detectar ciclos. Parámetros: - n (int): Término inicial. Variables: - max_pasos (int): Límite de seguridad para evitar bucles infinitos. - actual (int): Término actual de la sucesión. - previo1, previo2 (int): Memoria de los dos términos anteriores para detectar ciclos de período 1 y 2 sin usar listas. """ print(f"{n}", end="") # Inicio de la cadena con print en una línea max_pasos = 50 pasos = 0 actual = n previo1 = -1 previo2 = -2 # Corte por llegada a 1 (primos escapan a 1) while actual != 1 and pasos < max_pasos: siguiente = suma_alicuota(actual) print(f" {chr(0x2192)} {siguiente}", end="") # Detección de ciclos evaluando el estado anterior y el previo al anterior if siguiente == actual or siguiente == previo1 or siguiente == n: print(" (Ciclo detectado)") return # Actualización de la "ventana" de memoria para el próximo ciclo previo2 = previo1 previo1 = actual actual = siguiente pasos += 1 if actual == 1: print(" (Termina en 1)") else: print(" (Límite de pasos alcanzado sin detectar fin)") # ========================================== # SECCIÓN ALGORÍTMICA # ========================================== # 1) Prólogo print("--- Generador de Sucesiones Alícuotas ---") valor_inicial = int(input("Ingrese un entero n (n >= 2): ")) # 2) Desarrollo y 3) Epílogo if valor_inicial < 2: print("Error: n debe ser mayor o igual a 2.") else: # La función asume la responsabilidad de la impresión en línea print("Sucesión: ", end="") mostrar_sucesion_alicuota(valor_inicial) input("Pulse Enter para terminar el programa")