In [25]:
"""
IPython Notebook v4.0 para python 2.7
Librerías adicionales: Ninguna.
Contenido bajo licencia CC-BY 4.0. Código bajo licencia MIT. (c) Sebastian Flores.
"""

# Configuracion para recargar módulos y librerías 
%reload_ext autoreload
%autoreload 2

from IPython.core.display import HTML

HTML(open("style/iwi131.css", "r").read())


Out[25]:






IWI131

Programación de Computadores

Sebastián Flores

http://progra.usm.cl/

https://www.github.com/usantamaria/iwi131

Soluciones a Certamen 2, 1S 2014, Casa Central

Pregunta 1 [25%]

(a) Realice el ruteo de los siguientes programas e indique qué es lo que imprimen. Cada vez que el valor de una variable cambie, escríbalo en una nueva fila de la tabla. Recuerde que si una variable es de tipo string, debe colocar su valor entre comillas simples ’ ’. Si una variable almacena una función coloque el nombre de ésta como valor (sin comillas).

Pregunta 1.b : Impresiones

Indique lo que imprimen los siguientes programas.


In [ ]:
r,s = (2014,3,12),(2014,1,1)
t = (2014,2,1)
print r > s and s < t

In [ ]:
# DIGRESION: COMPARACION DE TUPLAS DEL MISMO LARGO
# Se verifican elementos en orden.
# El primer elemento que sea mayor, gana.
t1 = (0,1,2,3,4)
t2 = (10,0,0,0)
print t1<t2

In [ ]:
# DIGRESION: COMPARACION DE TUPLAS DE DISTINTO LARGO
# Se verifican elementos en orden.
# El primer elemento que sea mayor, gana
t1 = (0,1,2,3)
t2 = (0,1,2,3,4,5)
print t1<t2

In [ ]:
w = {'uno':[1,3],'dos':[2,4],
     'tres':[3,6]}
print w['uno'] + w['tres']

In [ ]:
def funcion1(a):
    a.reverse()
    return a

x = {1:[1, 0], 0:[0, 1]}
r = funcion1(x[0])[1]
print r

In [ ]:
def funcion2(x):
    if len(x) == 1:
        return x
    else:
        return x[-1] + funcion2(x[:-1])

print funcion2('FTW')

Pregunta 2 [35%]

El servicio de inteligencia de la UTFSM ha detectado una amenaza inminente a sus instalaciones por parte de un grupo terrorista que busca impedir que la universidad se convierta en el mejor centro educacional del mundo. Dada la gravedad de esta amenaza, se ha solicitado que la división de agentes “IWI-131” analice los datos obtenidos por los infiltrados que el servicio de inteligencia posee en otras universidades.

Los datos con los que se trabajará se encuentran en un diccionario llamado terroristas (variable global) que tiene por llave el identificador de cada terrorista y, por valor, una lista de tuplas que indica las universidades en las que ha sido visto el terrorista junto con la fecha correspondiente.

terroristas = {
2352: [('Stanfox', '2010-05-02'), 
       ('Hardyard', '2010-06-07'), 
       ('Yon Jopkins', '2010-05-02')],
1352: [('Stanfox', '2010-05-02'), 
       ('Stanfox', '2011-06-08')],
352: [('Hardyard', '2009-03-03')],
22: [('Yon Jopkins', '2012-11-16')]}

Un diccionario llamado experticias (variable global) que tiene por llave el identificador de cada terrorista y, por valor, la experticia de dicho terrorista.

experticias = { 2352:'TNT', 1352:'TNT', 
                352:'rayos laser', 22:'teletransportacion'}

In [ ]:
# CARGAR LOS DATOS

terroristas = {
2352: [('Stanfox', '2010-05-02'), 
       ('Hardyard', '2010-06-07'), 
       ('Yon Jopkins', '2010-05-02')],
1352: [('Stanfox', '2010-05-02'), 
       ('Stanfox', '2011-06-08')],
352: [('Hardyard', '2009-03-03')],
22: [('Yon Jopkins', '2012-11-16')]}

experticias = { 2352:'TNT', 1352:'TNT', 
                352:'rayos laser', 22:'teletransportacion'}

Pregunta 2.a

Desarrolle la función terroristas_se_conocen(terrorista1, terrorista2) que reciba como parámetros los identificadores de dos terroristas y que retorne True si ambos se conocen o False si no. Dos terroristas se conocen si ambos han sido vistos en el mismo lugar en la misma fecha.

>>> terroristas_se_conocen(2352, 1352)
True
>>> terroristas_se_conocen(2352, 352)
False

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Que estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [ ]:
def terroristas_se_conocen(terrorista1, terrorista2):
    lugares1 = set( terroristas[terrorista1] )
    lugares2 = set( terroristas[terrorista2] )
    return len(lugares1 & lugares2) > 0

print terroristas_se_conocen(2352, 1352)
print terroristas_se_conocen(2352, 352)

Pregunta 2.b

Desarrolle la función terroristas_que_han_estado_en(universidad) que reciba como parámetro el nombre de una universidad y que retorne un conjunto conformado por los identificadores de los terroristas que han sido visto en la universidad ingresada como parámetro.

>>> terroristas_que_han_estado_en('Stanfox')
set([1352, 2352])
>>> terroristas_que_han_estado_en('Prinxton')
set([])

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Que estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [ ]:
def terroristas_que_han_estado_en(universidad):
    terroristas_a_la_vista = set()
    for terrorista_id, terrorista_lugares in terroristas.items():
        for lugar, fecha in terrorista_lugares:
            if lugar==universidad:
                terroristas_a_la_vista.add(terrorista_id)
    return terroristas_a_la_vista

print terroristas_que_han_estado_en('Stanfox')
print terroristas_que_han_estado_en('Prinxton')

Pregunta 2.c

Desarrolle la función terroristas_clave() que retorne una lista de tuplas con los identificadores de los terroristas claves e informe si cada uno de ellos pertenece (True) o no (False) a una ”sleeper cell”.

  • Se considera que un terrorista es clave si es el único que posee cierta experticia.
  • Se considera que un terrorista pertenece a una ”sleeper cell” si es que no conoce a ningún otro terrorista.
>>> terroristas_clave()
[(22, True), (352, True)]

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Que estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [ ]:
def sleeper_call(terrorista_id):
    for tid in terroristas:
        if tid!=terrorista_id:
            if terroristas_se_conocen(tid, terrorista_id):
                return False
    return True
        
    
def terroristas_clave():
    # Obtener terroristas claves
    experticias_inv = {}
    for tid, exp in experticias.items():
        if exp not in experticias_inv:
            experticias_inv[exp] = []
        experticias_inv[exp].append(tid)
    lista_terroristas_claves = []
    for exp, lista_id in experticias_inv.items():
        if len(lista_id)==1:
            lista_terroristas_claves.append(lista_id[0])
    # Sleeper Call
    clave_y_sleeper_call = []
    for tid in lista_terroristas_claves:
        clave_y_sleeper_call.append( (tid, sleeper_call(tid)))
    # Return value
    return clave_y_sleeper_call

terroristas_clave()

Pregunta 3 [35%]

La gran maratón de Chago City es una de las carreras más importantes a nivel mundial. Debido a la gran cantidad de competidores que reúne este evento, se han generado las siguientes estructuras para ayudar con la organiación.

  • Diccionario con los inscritos, donde se almacena el número del corredor y los datos de éste.
inscritos = { #num_corredor: (rut,nombre,apellido,id_categoria,edad)
            1001: ('1111111-2', 'Carlos', 'Caszely', 2, 55),
            1002: ('223244-4', 'Marcelo', 'Rios', 3, 45),
            2129: ('3838292-1', 'Ivan', 'Zamorano', 4, 38),
            4738: ('5940301-2', 'Erika', 'Olivera', 5, 48),
            8883: ('3843993-1', 'Condor', 'ito', 3, 22),
            231: ('9492922-2', 'Pepe', 'Antartico', 3, 30)
            }
  • Diccionario con los inscritos, donde se almacena el número del corredor y los datos de éste.
categorias = { # id_categoria: (distancia, premio)
                1: ('1k', 10000),
                2: ('5k', 20000),
                3: ('10k', 450000),
                4: ('21k', 100000),
                5: ('42k', 250000)
                }
  • Lista de resultados, donde se registra el número del corredor y el tiempo que logró.
    # [ (num_corredor, tiempo) ]
    resultados = [(1001, '00:30:12'), (1002, '00:55:43'), 
                 (2129, '01:45:23'), (4738, '03:05:09'), 
                 (8883, '00:31:33'), (231, '00:39:45')]
    

In [ ]:
# CARGAR DATOS
inscritos = { #num_corredor: (rut,nombre,apellido,id_categoria,edad)
1001: ('1111111-2', 'Carlos', 'Caszely', 2, 55),
1002: ('223244-4', 'Marcelo', 'Rios', 3, 45),
2129: ('3838292-1', 'Ivan', 'Zamorano', 4, 38),
4738: ('5940301-2', 'Erika', 'Olivera', 5, 48),
8883: ('3843993-1', 'Condor', 'ito', 3, 22),
231: ('9492922-2', 'Pepe', 'Antartico', 3, 30)
}

categorias = { # id_categoria: (distancia, premio)
1: ('1k', 10000),
2: ('5k', 20000),
3: ('10k', 450000),
4: ('21k', 100000),
5: ('42k', 250000)
}

resultados = [(1001, '00:30:12'), (1002, '00:55:43'), 
              (2129, '01:45:23'), (4738, '03:05:09'), 
              (8883, '00:31:33'), (231, '00:39:45')]

In [ ]:
# OBSERVACION 

# Tenemos los resultados como una lista
resultados = [(1001, '00:30:12'), (1002, '00:55:43'), 
              (2129, '01:45:23'), (4738, '03:05:09'), 
              (8883, '00:31:33'), (231, '00:39:45')]
# Para buscar un resultado en particular (por ej, para 4738), tendriamos que recorrer toda la lista

# Pero podemos convertir a un diccionario de resultados

resultados_dict = dict(resultados)
print resultados_dict[2129]
print resultados_dict[231]

In [ ]:
# Esto es por una hermosa simetría en python
diccio = {"zero":0, "uno":1,"dos":2,"tres":3,"cuatro":4}
print diccio
l = diccio.items()
print l
d = dict(l)
print d

# Es decir, podemos convertir toda lista del tipo [(key1, val1), ..., (keyn, valn)] 
# en un diccionario {key1:val1, ..., keyn:valn}

Pregunta 3.a

Desarrolle la función competidores_edad(inscritos, categorias, min_edad, max_edad) que reciba el diccionario inscritos, el diccionario categorias y los valores enteros min_edad y max_edad (que representan la máxima y mínima edad).

La función debe retornar una lista de tuplas de todos los competidores que se encuentren entre la edad mínima y máxima (incluyéndolos), donde cada tupla contenga el nombre, apellido y la distancia a correr de un individuo.

>>> competidores_edad(inscritos,categorias,25,40)
[('Pepe', 'Antartico', '10k'), ('Ivan', 'Zamorano', '21k')]

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Que estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [ ]:
def competidores_edad(inscritos, categorias, min_edad, max_edad):
    corredores_en_edad = []
    for num_corredor, datos in inscritos.items():
        rut, nombre, apellido, id_categoria,edad = datos
        if min_edad<=edad<=max_edad:
            distancia, premio = categorias[id_categoria]
            tupla = (nombre, apellido, distancia)
            corredores_en_edad.append(tupla)
    return corredores_en_edad
    
print competidores_edad(inscritos,categorias,25,40)

Pregunta 3.b

Desarrolle la función tiempo_competidor(inscritos, resultados, rut) que reciba el diccionario inscritos, la lista de tuplas resultados y el string rut. La función debe retornar el tiempo, como cadena de texto, de un competidor en particular.

>>> tiempo_competidor(inscritos,resultados,'9492922-2')
'00:39:45'

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Que estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [ ]:
def obtener_numero_corredor(inscritos, rut_buscado):
    for num_corredor, datos in inscritos.items():
        rut, nombre, apellido, id_categoria,edad = datos
        if rut==rut_buscado:
            return num_corredor
    print "Not found"
    return ""

def tiempo_competidor(inscritos, resultados, rut):
    # Obtener el id_corredor
    num_corredor = obtener_numero_corredor(inscritos, rut)
    # Convertir resultados a un dict
    resultados_dict = dict(resultados)
    # Obtener el tiempo
    return resultados_dict[num_corredor]

print tiempo_competidor(inscritos,resultados,'9492922-2')

Pregunta 3.c

Desarrolle la función ganador_categoria(inscritos, categorias, resultados, distancia) que reciba el diccionario inscritos, el diccionario categorias, la lista de tuplas resultados y el string distancia. La función debe retornar una tupla con el ganador de la categoría, indicando el nombre, apellido y premio obtenido.

>>> ganador_categoria(inscritos, categorias, resultados, '10k')
('Condor', 'ito', 450000)

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Que estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [ ]:
def tiempo_en_segundos(tiempo_string):
    horas = int(tiempo_string[:2])
    minutos = int(tiempo_string[3:5])
    segundos = int(tiempo_string[6:])
    tiempo = horas*3600+minutos*60+segundos
    return tiempo

def ganador_categoria(inscritos, categorias, resultados, distancia):
    # Obtener id de la distancia
    id_distancia = 0
    premio_distancia = 0
    for idc, (dist, premio) in categorias.items():
        if dist==distancia:
            id_distancia = idc
            premio_distancia = premio
    # Convertir resultados a un dict
    resultados_dict = dict(resultados)
    # Obtener menor tiempo
    menor_tiempo = float("inf")
    nombre_ganador = ""
    apellido_ganador = ""
    for num_corredor, datos in inscritos.items():
        rut, nombre, apellido, id_categoria,edad = datos
        if id_categoria==id_distancia:
            tiempo = tiempo_en_segundos(resultados_dict[num_corredor])
            if tiempo<menor_tiempo:
                menor_tiempo = tiempo
                nombre_ganador = nombre
                apellido_ganador = apellido
    # Regresar ganador
    tupla_ganador = (nombre_ganador, apellido_ganador, premio_distancia)
    return tupla_ganador

ganador_categoria(inscritos, categorias, resultados, '10k')