En esta asignatura soy responsable de parte de un grupo de teoría y de dos de prácticas.

En mi grupo de teoría utilizo estos apuntes.

Además he preparado una colección de problemas cuyos enunciados están disponibles aquí. Dada la importante cantidad de ejercicios de examen de que se dispone, se hará un uso marginal de este documento.

Para trabajar en casa puedes utilizar  dev-cpp como Entorno Integrado de Desarrollo. Es gratuito y ocupa menos de 20MB. He preparado unos apuntes que explican a nivel introductorio el funcionamiento de este programa. No imprimir este documento, se ampliará a lo largo del curso. Las capturas de pantalla se ven mucho mejor en la versión en html del mismo documento.

Aquí iré publicando los ejercicios que se hagan en clase y cualquier otro material que vaya surgiendo a lo largo del curso.


Exámenes de otros años.

Luis Junco tiene en su página los exámenes de otros años recopilados en varios ficheros comprimidos.


En la misma página hay materiales interesantes en la zona de descargas.

2003-2004.
2004-2005.
2005-2006.

2006-2007.


Teoría:

Por petición popular incluyo aquí los materiales que usé el año pasado y esta año en al parte que estoy impartiendo.

Transparencias:


Introducción, para imprimir, para ver en el ordenador.


Estructuras básicas de algoritmos y de datos, parte I, para imprimir, para ver en el ordenador.


Estructuras básicas de algoritmos y de datos, parte II, para imprimir, para ver en el ordenador.

Estructuras básicas de algoritmos y de datos, parte III, para imprimir, para ver en el ordenador.

Programa de ejemplo. Fuente, para imprimir: pdf a dos columnas.

Definición de acciones no primitivas, parte I, para imprimir, para ver en el ordenador.

Definición de acciones no primitivas, parte II (Recursividad y un par de cosas más), para imprimir, para ver en el ordenador.

Definición de nuevos tipos de datos, parte I, para imprimir, para ver en el ordenador.

PROBLEMAS:

Ejemplos para if-else switch:

Resolver una ecuación de segundo grado considerando todos los casos posibles, si la ecuación tiene la forma ax^2+bx+c=0, se piden a, b y c por el teclado y:

Solución.

Pedir tres números por el teclado y mostrarlos por la pantalla ordenados de mayor a menor, intercambiando los valores de las variables adecuadas.

Solución.

Mostrar la fecha siguiente a una dada.

Solución.

Implementar una calculadora básica de números complejos, con las operaciones aritméticas habituales. Cuidar la presentación de los resultados de modo que:

Solución.

Los dos últimos ejercicios en un mismo pdf a dos columnas.

Ejemplos de bucles:

Ejemplos iniciales.


Ejemplos con bucles anidados.


Todos los ejemplos anteriores en un pdf a dos columnas ejercicios_bucles.pdf

Ejemplos de vectores.

Los ejemplos anteriores en un pdf a dos columnas ejercicios_vectores.pdf



Ejemplos introductorios de funciones.


Más ejemplos de funciones, relacionados con los temas de los apuntes "Mecanismos de paso de argumentos" y "Semántica del paso de argumentos". De alguna forma todos han caído en algún examen.

Los ejercicios anteriores en un mismo pdf a dos columnas. ejercicios_funciones.pdf

Ejemplos de enumeraciones, estructuras y clases.




Guiones de prácticas:

      1. Escribir un programa que pida un entero por el teclado y muestre por la pantalla sus divisores.

      2. Escribir un programa que pida un entero por el teclado y muestre por la pantalla la suma de los divisores del número.

      3. Escribir un programa que pida un entero por el teclado y muestre por la pantalla si el número es perfecto o no. Un número es perfecto si es igual a la suma de sus divisores (incluyendo el 1 pero no el propio número).

      4. Escribir un programa que pida un entero por el teclado y muestre por la pantalla un mensaje indicando si el número es primo o no.

      1. Escribir un programa que muestre por la pantalla los números primos menores que n, que se pide por el teclado.

      2. Escribir un programa que muestre por la pantalla los n primeros primos, n se pide por el teclado. Se puede utilizar el siguiente esquema:

#include<iostream>
using namespace std;
int main()
{
//n es el numero de primos que se desean
//conta es el contador de primos
//actual es cada uno de los enteros
//que se comprueban si son o no primos
int conta,n,actual;
//inicializar conta y actual
...;
...;
//pedir el numero de primos que se desean
...;
//mientras el numero de primos ENCONTRADOS
//sea menor que el que nos piden
while(...)
        {
        //declarar e inicializar es_primo
        bool ...;
                //comprobar si existe algun divisor
                for (...)
                        {
                        //si se encuentra un divisor
                        if (...)
                                //es falso que sea primo
                                ...;
                        }
        //si (finalmente) es primo
        if (...)
                {
                //mostrarlo por la pantalla
                ...;
                //contarlo
                ...;
                }
        //en cualquier caso, actualizar actual
        ...;
        }
}
      1. Escribir un programa que muestre por la pantalla los n primeros números perfectos. Utilizar un esquema similar al anterior.

        1. Escribir un programa que pida un entero "numero" por el teclado y una cifra "c" y que muestre por la pantalla si el entero contiene dicha cifra. Se puede usar este esquema, no siendo óptimo, es más fácil de reutilizar en el ejercicio que va a continuación. Es necesario añadir las directivas del preprocesador y demás detalles.

          //esqueleto para el primer ejercicio de la práctica 3
          ...
          int main()
          {
            //numero es el número en donde se busca c 
            int numero,c,copia;
            bool encontrada;
            //pedir los datos
            ...
            //inicialmente no se ha encontrado la cifra
            ...
            //se copia el numero
            ...
            //mientras queden cifras en copia y no haya encontrado la cifra
            while(...)
              {
                //si la encuentro
                if(...)
                  //marco que la he encontrado (cambiar el valor de "encontrada"
                  ...
                //quito la cifra del numero
                ...;   
              }
            //acabado el while, si la he encontrado
            //muestro el resultado
            if(...)
              ...
            else
              ...
          }    
        1. Escribir un programa que pida un entero "n" por el teclado y una cifra "c", mostrando por la pantalla los "n" primeros números naturales que contienen a esa cifra. Usar un esquema similar al del segundo ejercicio de la práctica anterior.

- Escribir una función booleana que devuelva true si un número que se pasa como parámetro es

poderoso, false en caso contrario.

- Escribir una función booleana que devuelva true si un número que se pasa como parámetro es

potencia perfecta, false en caso contrario.

- Utilizar las dos anteriores para escribir una función que devuelva true si un número es de Aquiles,

false en caso contrario.

Ejemplo:

108 es un número de Aquiles, 108=2^2*3^3 y además no existen m y k / m^k=108

NOTA 1: escribir un programa para probar cada una de las funciones que se han escrito. Enviar ese programa por correo. Aunque no se pide, escriba o copie de los apuntes la función int potencia(int,int); que eleva un número entero a un exponente también entero.

NOTA 2: aunque no se pide, puede escribir o copiar de los apuntes la función int potencia(int,int); que eleva un número entero a un exponente también entero, puede serle útil.

NOTA 3: para probar si existen x e y tales que cumplan una determinada propiedad (si no nos interesan los valores que tomen, sólo si existen o no) se pueden utilizar dos bucles for anidados:

for (int x=limInfX;x<limSupX;x++)

for (int y=limInfY;y<limSupY;y++)

{

//probar si se cumple la condición

...

//si se cumple retornar true

}

//si se llega a este punto (fuera de los bucles)

//no se han encontrado

//retornar false

...

  1. Escribir una función que reciba un entero positivo y devuelva su número de divisores. Ejemplo, si el entero es 6 la función devolverá 4 ya que los divisores de 6 son 1, 2, 3 y 6. Escribir un programa de prueba y enviarlo por correo.

  2. Usando la anterior, escribir una función booleana que reciba un entero positivo y devuelva true si es altamente compuesto, false en caso contrario. Escribir un programa de prueba y enviarlo por correo.

Ejemplo, si el entero es 6 la función devuelve true porque 5 tiene 2 divisores, 4 tiene 3, 3 tiene 2, 2

tiene 2 y 1 tiene 1. Por el contrario, si el entero es 5 la función devuelve false.

Si acaba con tiempo, puede escribir un programa que muestre los x primeros números altamente compuestos, x se pide por el teclado y enviarlo por correo. Aquí puede comprobarse el resultado.

Tomando como punto de partida el código de ejemplo que figura al final del enunciado, ampliarlo, añadiendo las operaciones indicadas. A elección del alumno, usando funciones u operadores, salvo en los casos en los que se especifique una alternativa concreta..

Escribir un programa que utilice las operaciones anteriores para efectuar el cálculo que se expresa a continuación en notación algebraica:

tipifica(A*B+C'-D)

y que muestre el resultado por la pantalla. A, B, C, D son matrices de dimensiones 3x4, 4x3, 3x3, 3x3 respectivamente. Comprobar el resultado utilizando Matlab o calculadora. Seleccionar el resultado de la ejecución del programa y pegarlo en el cuerpo del mensaje en donde se adjunte el código fuente del programa.

Añadir las operaciones básicas con vectores:

Idear una expresión adecuada para probar todas las funciones/operadores implementados. Escibir un programa en el que se calcule el valor de dicha expresión para unos valores escogidos por ud.

NOTA 1: de cara a la corrección, me es indiferente que las funciones devuelvan el resultado con return o se utilice un argumento pasado por referencia no constante. Evidentemente el cálculo pedido se escribirá de forma distinta.

NOTA 2: para mayor comodidad se han sobrecargado >> y << para vector<vector<float> >. Si no se hubiese hecho, no se podrían utilizar estos operadores con matrices.

Código de ejemplo:

#include<iostream>
using namespace std;
#include<vector>
//sobrecarga del operador * para matrices
vector<vector<float> >  operator*(const vector<vector<float> > &a, const vector<vector<float> > &b)
{ 
  //el vector resultado tiene de dimensiones el numero de filas
  //de a y el numero de columnas de b   
  vector<vector<float> > c(a.size(),vector<float>(b[0].size()));
  //se recorre la matriz resultado
  for (int i=0;i<a.size();i++)
    for (int j=0;j<b[0].size();j++)
      {
        //se inicializa el elemento i j del resultado a cero      
        c[i][j]=0;
        //se recorre la fila i de a y la columna j de b
        //multiplicandolas escalarmente
        for (int k=0;k<a[0].size();k++)
          c[i][j]+=a[i][k]*b[k][j];
      }
  return c;
}
//sobrecarga del operador << para matrices
//se pasa por referencia no constante un flujo de salida
//se devuelve el flujo de salida modificado
ostream& operator<<(ostream& o,const vector<vector<float> > &a)

{
  for (int i=0;i<a.size();i++)
    {
      for (int j=0;j<a[0].size();j++)
        //se insertan el elemento en el flujo de salida    
        o<<a[i][j]<<' ';
      o<<endl;
    }    
  //se devuelve el flujo de salida
  return o;
}
//sobrecarga del operador >> para matrices
//se pasa por referencia no constante un flujo de entrada
//se devuelve el flujo de entrada modificado
istream& operator>>(istream& in, vector<vector<float> > &a)
{
  for (int i=0;i<a.size();i++)
    {
      for (int j=0;j<a[0].size();j++)    
        {
          cout<<'['<<i<<"]["<<j<<"]=";
          //se extrae el elemento del flujo de entrada
          in>>a[i][j];
        }    
    }    
  //se devuelve el flujo de entrada
  return in;
}

int main()
{
  int fa,ca,cb;
  cout<<"filas de a, columnas de a, columnas de b:";
  cin>>fa>>ca>>cb;
  vector<vector<float> > a(fa,vector<float>(ca)),b(ca,vector<float>(cb));
  //esto solo se puede hacer si se han sobrecargado
  //los operadores correspondientes
  cin>>a;
  cin>>b;
  cout<<a*b;
}
//juego del sokoban (tb conocido como "mueve la caja")
//consiste en empujar una serie de cajas u objetos dispuestas en el tablero
//con el fin de situarlas encima de unas marcas
//el juego termina cuando se situan todas las cajas encima de 
//las marcas. Por lo tanto tiene que haber tancas cajas como marcas.
//No se puede:
//"Tirar" de las cajas, solo empujar
//Mover una caja pegada al borde del tablero
//no se pueden empujar dos o mas cajas
#include<iostream>
#include<vector>
using namespace std;

        //devuelve true si todas las marcas estan cubiertas
        //por los objetos. Se pueden contar las marcas descubiertas
        //y retornar true si son cero o leer las transparencias de vectores
        bool fin(vector<vector<bool> > marcas, vector<vector<bool> > objetos)
        {
        ...
        }  

       //inicializaTablero asigna el tama$-3õ½o a los vector<vector<bool> >
       //que representan las marcas y los objetos
       //situa las marcas y los objetos en el tablero
       //y al protagonista del juego en determinada posicion
       //por ejemplo, en esta situacion:
       //  +-+-+-+-+-+
       //  |*| | | | |
       //  +-+-+-+-+-+
       //  | |X|#| | |
       //  +-+-+-+-+-+
       //  | | | | | |
       //  +-+-+-+-+-+
       //  | | | | | |
       //  +-+-+-+-+-+
       //  | | | | | |
       //  +-+-+-+-+-+
       // marcas[1][1] es true (se muestra como una X)
       // objetos[1][2] es true (se muestra como una #)
       // el protagonista esta en 0,0 luego i_p es 0 y
       // j_p es tambien 0. El personaje se representa por un *
        void inicializaTablero(vector<vector<bool> > &marcas, vector<vector<bool> > &objetos, int &i_p, int &j_p)
        {
        ...
        } 

  
        //mover recibe como parametro la direccion, un caracter
        //que puede ser u,d,l,r denotando arriba abajo izq o dcha
        //se pueden utilizar variables de tipo entero d_i y d_j
        //para representar los incrementos que se le dan a la posicion
        //del personaje, si el caracter es u el incremento seria -1
        //ya que para "subir" se decrementa la fila (i_p) en donde esta
        //el personaje. De forma similar para las otras direcciones.
        //Por lo tanto, si el movimiento es posible se modifica la 
        //posicion del protagonista y si este empuja una caja que se puede
        //mover, se modifica de forma conveniente el atributo objetos. 
        void mover(char direccion, vector<vector<bool> > &marcas, vector<vector<bool> > &objetos,int &i_p, int &j_p)
        {
        ...
        }    
        //muestra el tablero de modo que:
        //si coinciden personaje y marca se ve el personaje
        //si coinciden objeto y marca se ve el objeto
        void muestra(const vector<vector<bool> > &marcas, const vector<vector<bool> > &objetos, int i_p, int j_p)
        {
        ...
        }    
    
int main()
{
    //marcas es un vector de bool del tama$-3õ½o del tablero
    //true significa que ahi hay que poner un objeto
    vector<vector<bool> > marcas;
    //objetos es un vector de bool del tama$-3õ½o del tablero
    //representa los objetos y sus posiciones
    vector<vector<bool> > objetos;
    //estos dos enteros representan la posicion del protagonista
    //del juego
    int i_p,j_p;
   //declarar variable para pedir direccion
    char direccion;
    //inicializar el tablero
    ...
    //mientras no esten todas las marcas
    //cubiertas con objetos
    while(...)
       {
          //mostrar el tablero
           ...
           //pedir movimiento
           ...
           //actualizar tablero, llamar a mover con
           //direccion como parametro
           ...
       }    
       //mostrar el tablero como queda al final
       ...
       system("PAUSE");
}    

//Ejemplo de ejecucion:
//
//+-+-+-+-+-+
//|*| | | | |
//+-+-+-+-+-+
//| |X|#| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento r
//
//+-+-+-+-+-+
//| |*| | | |
//+-+-+-+-+-+
//| |X|#| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento r
//
//+-+-+-+-+-+
//| | |*| | |
//+-+-+-+-+-+
//| |X|#| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento r
//
//+-+-+-+-+-+
//| | | |*| |
//+-+-+-+-+-+
//| |X|#| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento d
//
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| |X|#|*| |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento l
//
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| |#|*| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Presione una tecla para continuar . . .
//con clases
#include<iostream>
#include<vector>
using namespace std;
class tablero{
   //marcas es un vector de bool del tama�o del tablero
   //true significa que ahi hay que poner un objeto
    vector<vector<bool> > marcas;
    //objetos es un vector de bool del tama�o del tablero
    //representa los objetos y sus posiciones
    vector<vector<bool> > objetos;
    //estos dos enteros representan la posicion del protagonista
    //del juego
    int i_p,j_p;
    public:
       //el constructor por defecto asigna el tama�o a los atributos
       //de tipo vector, situa las marcas y los objetos en el tablero
       //y al protagonista del juego en determinada posicion
       //por ejemplo, en esta situacion:
       //  +-+-+-+-+-+
       //  |*| | | | |
       //  +-+-+-+-+-+
       //  | |X|#| | |
       //  +-+-+-+-+-+
       //  | | | | | |
       //  +-+-+-+-+-+
       //  | | | | | |
       //  +-+-+-+-+-+
       //  | | | | | |
       //  +-+-+-+-+-+
       // marcas[1][1] es true (se muestra como una X)
       // objetos[1][2] es true (se muestra como una #)
       // el protagonista esta en 0,0 luego i_p es 0 y
       // j_p es tambien 0. El personaje se representa por un *
        tablero()
        {
        //...
        } 
        //devuelve true si todas las marcas estan cubiertas
        //por los objetos. Se pueden contar las marcas descubiertas
        //y retornar true si son cero o bien PENSAR   
        bool fin(void)
        {
        //...
        }    
        //mover recibe como parametro la direccion, un caracter
        //que puede ser u,d,l,r denotando arriba abajo izq o dcha
        //se pueden utilizar variables de tipo entero d_i y d_j
        //para representar los incrementos que se le dan a la posicion
        //del personaje, si el caracter es u el incremento seria -1
        //ya que para "subir" se decrementa la fila (i_p) en donde esta
        //el personaje. De forma similar para las otras direcciones.
        //Por lo tanto, si el movimiento es posible se modifica la 
        //posicion del protagonista y si este empuja una caja que se puede
        //mover, se modifica de forma conveniente el atributo objetos. 
        void mover(char direccion)
        {
        ...
        }
        //muestra el tablero de modo que:
        //si coinciden personaje y marca se ve el personaje
        //si coinciden objeto y marca se ve el objeto
        void muestra(void)
        {
        //...
        }    
    };

int main()
{
   //declarar variable para pedir direccion
    ... ...;
    //declarar tablero
    ... ...;
    //mientras no esten todas las marcas
    //cubiertas con objetos
    //llamada a fin
    while(...)
       {
          //mostrar el tablero
           //llamada a muestra
           //...
           //pedir movimiento
           cout<<"Introduce movimiento ";
           cin>>...;
           //actualizar tablero, llamar a mover con
           //direccion como parametro
           //...
       }    
       //mostrar el tablero como queda al final
       //llamada a muestra
       //...
       system("PAUSE");
}    
//Una ejecucion completa de ejemplo:
//
//+-+-+-+-+-+
//|*| | | | |
//+-+-+-+-+-+
//| |X|#| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento r
//
//+-+-+-+-+-+
//| |*| | | |
//+-+-+-+-+-+
//| |X|#| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento r
//
//+-+-+-+-+-+
//| | |*| | |
//+-+-+-+-+-+
//| |X|#| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento r
//
//+-+-+-+-+-+
//| | | |*| |
//+-+-+-+-+-+
//| |X|#| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento d
//
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| |X|#|*| |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Introduce movimiento l
//
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| |#|*| | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//| | | | | |
//+-+-+-+-+-+
//Presione una tecla para continuar . . .