Está en la página 1de 5

Ingeniería de Sistemas y Computación

ISIS1105 – Diseño y análisis de algoritmos


Sección 2. Profesor: Jorge Duitama
Semestre: 2017-20

Solución Tarea 1

Describir los datos de entrada, los datos de salida y especificar en forma de predicado
de lógica proposicional o lógica de primer orden la precondición y la postcondición
para los siguientes problemas:

1. Dado un número natural, encontrar su raíz cuadrada entera, la cual se define como
el mayor número natural que es menor que la raiz cuadrada real del número

Entrada:
- Número natural:
var n: nat

Salida
- Número natural que representa la raiz cuadrada entera.
var r: nat

Precondición: Como la raiz cuadrada entera se puede calcular para cualquier número
natural, no se pide ninguna condición particular sobre la entrada. Se puede usar una
constante A para asegurar que el programa no va a modificar la entrada para forzar
que la postcondición se cumpla:

{Q: n=A}

Postcondición: Expresando el objetivo en términos de la entrada y la salida, se busca


un número tal que

r ≤ √A ≤ r+1

Como la función x2 es creciente en los números reales, la postcondición también se


puede expresar de esta forma que no requiere el uso de raices cuadradas:

{R: r2 ≤ A ≤ (r+1)2}
2. Dado un número natural, determinar si es un número primo

Entrada:
- Número natural:
 var n: nat

Salida
- Variable booleana que debe ser true si el número es primo y false de lo contrario
 var b: bool

Precondición: Como para cualquier número natural se puede determinar si es primo, no


se pide ninguna condición particular sobre la entrada. Se puede usar una constante A
para asegurar que el programa no va a modificar la entrada para forzar que la
postcondición se cumpla:

{Q: n=A}

Postcondición: El valor de b (true o false) tiene que coincidir al final con el valor de
verdad de un predicado que solo sea cierto si n es primo. Según la definición de
número primo, el predicado debe indicar que ningún número entre 2 y n-1 puede
dividir a n, o en otras palabras, que el residuo entre n y cualquiera de estos números
debe ser mayor que cero. La postcondición hace entonces equivalente el valor de b al
valor del predicado:

{R: b = (∀ k | 2 ≤ k < A : A mod k > 0)}

3. Dado un número primo, encontrar el siguiente número primo

Entrada:
- Número natural
 var n: nat

Salida
- Número natural que representa el siguiente número primo
 var p: nat

Precondición: Como normalmente no hay un tipo de dato específico para números


primos, pedimos como condición de inicio que el número de entrada n sea primo.
Como este predicado lo vamos a necesitar también en la postcondición, lo vamos a
definir con el nombre PR para cualquier número natural x:

PR(x) =  (∀ k | 2 ≤ k < x : x mod k > 0)

{Q: PR(n)}
Postcondición: Utilizando el mismo predicado para verificar primalidad, pedimos al final
que p sea mayor que n, que p sea primo y que níngun número entre n y p sean primos

{R: n < p Λ PR(p) Λ (∀ k | n < k < p : ¬ PR(k)}

4. Dado un arreglo de números enteros, encontrar el elemento más grande del arreglo

Entrada:
- Arreglo de números enteros de tamaño N. Se puede utilizar indices estilo java
  var a[0,N): array of int

Salida
- Número entero que representa el elemento más grande en el arreglo
 var x: int

Precondición: El máximo se puede calcular para cualquier arreglo de números.

{Q: true}

Postcondición: El elemento más grande debe ser un elemento del arreglo y además
tiene la propiedad de que todos los elementos del arreglo son menores o iguales que
él. Los dos predicados se pueden expresar con cuantificadores sobre los índices del
arreglo:

{R: (∃ k | 0 ≤ k < N : a[k] = x) Λ (∀ k | 0 ≤ k < N : a[k] ≤ x)}

alternativamente se puede utilizar el cuantificador max:

{R: x=(max k | 0 ≤ k < N : a[k]) }

5. Dado un conjunto de estudiantes ordenados por código y el código de un estudiante,


encontrar el estudiante con el código dado o reportar que el estudiante no existe

Como el enunciado nos habla de estudiantes, debemos representar el tipo de dato


Estudiante. En este caso asumamos que de una variable e de tipo Estudiante podemos
saber su código y su nombre con las expresiones e.codigo y e.nombre respectivamente

Entradas:
- Lista de estudiantes. Se asume que todos los estudiantes tienen un código distinto y
por eso es un conjunto. Como los estudiantes deben estar ordenados, es mejor
representarlos con un arreglo de tamaño N.
 var E[0,N): array of Estudiante

- Código del estudiante a buscar


 var c: string
Salida:
- Estudiante con el código buscado. Esta variable puede asumir el valor nulo (⊥) si no
hay estudiantes en el conjunto con el código buscado
  var e: Estudiante

Precondición: Dado que se escogió un arreglo para representar los estudiantes, se


debe validar como precondición que el arreglo no tenga repetidos. Además se va a
pedir que esté ordenado por código. Las dos condiciones se pueden describir con un
solo predicado:

{Q: (∀ k | 0≤ k< N­1 : E[k].codigo < E[k+1].codigo)}

Postcondición: Como hay dos posibilidades, que el estudiante esté o que no esté, se
utiliza una disyunción y se expresa cual es el valor de la variable de salida en cada uno
de los dos casos:

{R: (e=⊥  Λ (∀k | 0≤k<N : E[k].codigo ≠ c)) V (e ∈ E  Λ e.codigo=c) }

Para el segundo predicado se utilizó notación de conjuntos para que sea más facil
expresar que e es uno de los estudiantes del arreglo E, el cual por la precondición
tambien es un conjunto.

6. Dada la base de datos con los usuarios de Facebook y las relaciones de amistad
entre ellos, encontrar el subconjunto más grande de usuarios en el que todos los
usuarios se conozcan entre ellos

Como el enunciado nos habla de usuarios, debemos representar el tipo de dato


Usuario. Asumamos que de una variable u de tipo Usuario podemos saber su nombre y
su correo electrónico con las expresiones u.nombre y u.correo respectivamente

Entradas:
- Conjunto de usuarios. Se asume que todos los usuarios tienen un correo electrónico
distinto con el que se identifican y por eso es un conjunto. En este caso se van a usar
conjuntos en lugar de arreglos:
 var U: set of Usuario

- Relaciones de amistad entre usuarios. Conjunto de parejas de usuarios que están


relacionados
 var E: set of Usuario x Usuario

Esta definición describe los componentes principales de un grafo no dirigido, por lo


cual de manera alternativa se podría definir la entrada como un grafo no dirigido de
usuarios en el que los ejes sean las relaciones de amistad
 var G(U,E): graph of Usuario

Salida:
- Máximo subconjunto de usuarios tal que todos los usuarios del subconjunto estén
conectados entre ellos:
 var V: set of Usuario

Precondición: En cualquier grafo de relaciones entre usuarios se debe poder encontrar


el subconjunto más grande con las características dadas:

{Q: true}

Postcondición: Se deben cumplir tres cosas sobre el conjunto de salida V:


1) Que sea subconjunto de U
2) Que todos los elementos de V esten relacionados entre ellos y
3) Que en cualquier otro subconjunto de U más grande se encuentre al menos una
pareja que no tenga relación

Las tres condiciones se pueden expresar como predicados que se unirían con
conjunciones:

{R: (V ⊆ U Λ (∀a,b | a ≠ b Λ a ∈ V Λ b ∈ V : {a,b} ∈ E) Λ 
    (∀W | W⊆U Λ |W|>|V| : (∃ a,b | a ≠ b Λ a ∈ W Λ b ∈ W : {a,b} ∉ E)))}

Alternativamente, se puede definir el predicado CL para cualquier subconjunto de U


que sea cierto si todos sus elementos están conectados entre ellos:

CL(X) = (∀a,b | a ≠ b Λ a ∈ X Λ b ∈ X : {a,b} ∈ E)

Con esta definición la postcondición se escribe así:

{R: (V ⊆ U Λ CL(V) Λ (∀W | W ⊆ U Λ |W|>|V| : ¬ CL(W)) )}  

También podría gustarte