Solución al Trabajo Práctico - Junio de 2018 EJERCICIO 1 Supongamos que f(x) es una función definida en (, ) y cuyas derivadas hasta cierto orden son continuas. Desconocemos la expresión de la función. Sin embargo, conocemos el valor de la función para un conjunto de n + 1 valores diferentes de x, en general no equiespaciados, que llamaremos {x 0, x 1,..., x n. Estos valores de x se denominan nodos de interpolación. Llamaremos {y 0, y 1,..., y n a los valores conocidos de la función en dichos puntos: y i = f(x i ). x f(x) x 0 y 0 x 1 y 1.. x n y n El problema que nos planteamos consiste en encontrar el valor de f(x) para un valor de x, diferente de los nodos de interpolación, pero que se encuentra en la vecindad de alguno de ellos. Aplicaremos para ello la técnica de interpolación polinómica. La función f(x) es aproximada por un polinomio ϕ n (x) de grado menor o igual a n, que satisface ϕ n (x) = a 0 +a 1 x+a 2 x 2 + +a n x n y i = ϕ n (x i ) para todo i = 0,1,...,n
El polinomio, escrito en la forma de Lagrange, es el siguiente: ϕ n (x) = c 0 (x x 1 ) (x x 2 ) (x x n )+ c 1 (x x 0 ) (x x 2 ) (x x n )+... c r (x x 0 ) (x x 1 ) (x x r 1 ) (x x r+1 ) (x x n )+... c n (x x 0 ) (x x 1 ) (x x n 1 ) donde los coeficientes c 0,c 1,...,c n se calculan imponiendo que satisfagan: y 0 = ϕ n (x 0 ), y 1 = ϕ n (x 1 ),... y n = ϕ n (x n ) Se obtiene: c 0 = c 1 =... c n = y 0 (x 0 x 1 ) (x 0 x 2 )...(x 0 x n ) y 1 (x 1 x 0 ) (x 1 x 2 )...(x 1 x n ) y n (x n x 0 ) (x n x 1 )...(x n x n 1 ) Sustituyendo el valor de los coeficientes en el polinomio, se obtiene la fórmula de interpolación de Lagrange: ϕ n (x) = (x x 1) (x x 2 )...(x x n ) y 0 (x 0 x 1 ) (x 0 x 2 )...(x 0 x n ) + (x x 0 ) (x x 2 )...(x x n ) y 1 (x 1 x 0 ) (x 1 x 2 )...(x 1 x n ) +... (x x 0 ) (x x 1 )...(x x n 1 ) y n (x n x 0 ) (x n x 1 )...(x n x n 1 ) Escriba un programa en C++ que realice las acciones siguientes. 1. Solicitar al usuario que introduzca por consola el número de nodos de interpolación. Leer el valor, almacenándolo en una variable llamada N. Si el valor leído es menor que 2, terminar. 2 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2018 2. Solicitar al usuario que introduzca por consola losn pares de valoresx i,y i. Leer los valores, almacenándolos en sendos vectores llamadosxi, yi. 3. Mostrar en la consola los N pares de valores introducidos por el usuario. 4. Solicitar al usuario que introduzca por consola un punto x donde interpolar la función. Leer el valor, almacenándolo en una variable llamada x. 5. Calcular el valor en x de la fórmula de interpolación de Lagrange y escribir el resultado en la consola, en formato científico con 4 dígitos decimales. 6. Terminar. Solución al Ejercicio 1 #include <iostream> #include <limits> #include <vector> #include <iomanip> int main() { // Número de nodos de interpolación int N; std::cout << "Numero nodos de interpolacion:\n"; if (!(std::cin >> N) N<2 ) { std::cout << "Valor no valido" << std::endl; std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); Dpto. de Informática y Automática, UNED 3
// Pares de valores xi, yi std::vector<double> xi, yi; for (int i=0; i<n; i++) { double val; std::cout << "x" << i << " = \n"; if ( std::cin >> val ) { xi.push_back(val); else { std::cout << "Valor no valido" << std::endl; std::cout << "y" << i << " = \n"; if ( std::cin >> val ) { yi.push_back(val); else { std::cout << "Valor no valido" << std::endl; // Valores std::cout << "xi\tyi" << std::endl; for (unsigned int i=0; i<xi.size(); i++) std::cout << xi[i] << "\t" << yi[i] << std::endl; // Punto donde interpolar double x; std::cout << "x = " << std::endl; if (!(std::cin >> x) ) { std::cout << "Valor no valido" << std::endl; // Fórmula de interpolación de Lagrange double y = 0; for (unsigned int i=0; i<xi.size(); i++) { double p = 1; for (unsigned int j=0; j<xi.size(); j++) if ( i!= j ) p *= ( x - xi[j] ) / ( xi[i] - xi[j] ); y += p*yi[i]; // Salida por consola std::cout << "y = " << std::scientific << std::setprecision(4) << y << std::endl; 4 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2018 EJERCICIO 2 En criptografía existe un conjunto de técnicas para el cifrado de los mensajes denominado cifrado por transposición, que consiste en cambiar el orden de escritura de las letras que componen el texto del mensaje. Una de estas técnicas consiste en escribir las letras del mensaje alternativamente en dos líneas, una situada encima de la otra. La secuencia de letras de la línea inferior es entonces concatenada a continuación de la secuencia de la línea superior, para formar el texto cifrado. A continuación se muestra un ejemplo. EL ENCUENTRO SERA EL PROXIMO LUNES EN LA ESTACION E E C E T O E A L R X M L N S N A S A I N L N U N R S R E P O I O U E E L E T C O EECETOEALRXMLNSNASAINLNUNRSREPOIOUEELETCO El receptor puede recuperar el mensaje invirtiendo el procedimiento. Escriba un programa en C++ que realice las acciones siguientes. 1. Declarar una constante de tipo string llamada mensaje, asignándole el valor: EL ENCUENTRO SERA EL PROXIMO LUNES EN LA ESTACION. 2. Reordenar las letras aplicando la técnica de cifrado descrita anteriormente. Almacenar el texto cifrado en una variable de tipo string llamada cifrado. 3. Mostrar en la consola el contenido de la variable cifrado. 4. Ejecutar el procedimiento inverso, a fin de recuperar el mensaje original sin espacios en blanco a partir del texto cifrado. Mostrar el mensaje descifrado en la consola. 5. Terminar. Dpto. de Informática y Automática, UNED 5
Solución al Ejercicio 2 #include<iostream> #include<string> #include<sstream> const std::string mensaje = "EL ENCUENTRO SERA EL PROXIMO LUNES EN LA ESTACION"; int main() { // Cifrado std::stringstream lineasup, lineainf; bool enlineasup = true; for (unsigned int i=0; i<mensaje.size(); i++) { if ( mensaje[i]!= ' ' ) { if (enlineasup) { lineasup << mensaje[i]; enlineasup = false; else { lineainf << mensaje[i]; enlineasup = true; std::string cifrado = lineasup.str() + lineainf.str(); std::cout << "Mensaje cifrado:\n" << cifrado << std::endl; // Descifrado std::stringstream msg; unsigned int len = cifrado.size() / 2; unsigned int resto = cifrado.size() % 2; for (unsigned int i=0; i<len; i++) { msg << cifrado[i] << cifrado[i+len+resto]; if (resto) msg << cifrado[len]; std::cout << "Mensaje descifrado:\n" << msg.str() << std::endl; 6 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2018 EJERCICIO 3 Otro conjunto de técnicas criptográficas se denomina cifrado por sustitución. En este caso, el mensaje cifrado se obtiene sustituyendo cada letra del mensaje original por otra letra, empleando para ello un determinado algoritmo. Uno de los métodos de sustitución más sencillos es obtener el alfabeto cifrado desplazando el alfabeto original un cierto número N de posiciones. A continuación se muestra un ejemplo, en el cual el alfabeto cifrado se obtiene desplazando 3 posiciones el alfabeto original. Aplicaremos el convenio de emplear letras minúsculas para escribir el texto original y letras mayúsculas para el texto cifrado. Hemos excluido la letra ñ de los alfabetos. Original: Cifrado: a b c d e f g h i j k l m n o p q r s t u v w x y z D E F G H I J K L M N O P Q R S T U V W X Y Z A B C A continuación puede verse un ejemplo de aplicación de este cifrado. Obsérvese que los espacios en blanco del mensaje original se mantienen como tales en el mensaje cifrado, y que cada letra del mensaje es sustituida por su correspondiente del alfabeto cifrado. el encuentro sera el proximo lunes en la estacion HO HQFXHQWUR VHUD HO SURALPR OXQHV HQ OD HVWDFLRQ Escriba un programa en C++ que realice las acciones siguientes. 1. Mostrar un mensaje en la consola solicitando al usuario que introduzca por consola el número entero N. Leer el valor introducido por el usuario. Si dicho valor es menor que 1 o mayor que 25, mostrar en la consola un aviso indicándolo y terminar. 2. El alfabeto original es: a b c d e f g h i j k l m n o p q r s t u v w x y z El alfabeto cifrado se obtiene reemplazando cada letra por su mayúscula y desplazando N posiciones, tal como se mostró en el ejemplo anterior. Escribir en la consola el alfabeto original y el alfabeto cifrado. Dpto. de Informática y Automática, UNED 7
3. Solicitar al usuario que introduzca por consola el mensaje a cifrar. Leer el texto introducido por consola y almacenarlo en una variable de tipo string llamada mensaje. 4. Comprobar que el mensaje a cifrar está compuesto por uno o más caracteres del alfabeto original, y por cero, uno o más espacios en blanco. Si el texto introducido por el usuario no pasa esta comprobación, mostrar por consola un aviso indicando qué caracteres del mensaje no son válidos y terminar. 5. Generar el correspondiente mensaje cifrado por sustitución. Almacenar el mensaje cifrado en una variable de tipo string llamada cifrado. 6. Ejecutar el procedimiento inverso, a fin de recuperar el mensaje original a partir del mensaje cifrado. Almacenar el texto obtenido en una variable de tipo string llamada descifrado. 7. Mostrar en la consola los tres mensajes: el mensaje original, el cifrado y el descifrado. 8. Comprobar que los mensajes original y descifrado son iguales. 9. Terminar. 8 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2018 Solución al Ejercicio 3 #include <iostream> #include <limits> #include <string> #include <sstream> const std::string alf_m = "abcdefghijklmnopqrstuvwxyz"; const std::string alf_m = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int main() { // Entrada por consola de N y comprobación int N; std::cout << "Introduzca N:" << std::endl; std::cin >> N; if ( N<1 N>25 ) { std::cout << "ERROR: valor de N no valido"; std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ------------------------ // Generar alfabeto cifrado // ------------------------ std::string alf_c = alf_m.substr(n,alf_m.length()-n) + alf_m.substr(0,n); // ------------------------------- // Mostrar alfabetos en la consola // ------------------------------- std::cout << "Original:\t" << alf_m << "\ncifrado:\t" << alf_c << std::endl; Dpto. de Informática y Automática, UNED 9
// ---------------------------------------------- // Entrada por consola del mensaje y comprobación // ---------------------------------------------- std::string mensaje; std::cout << "Introduzca mensaje:" << std::endl; getline(std::cin, mensaje); // Comprobación - Longitud del mensaje>0 if (mensaje.length() == 0) { std::cout << "ERROR: Mensaje con cero caracteres" << std::endl; // Comprobación - No solo contiene espacios bool mensajeenblanco = true; for (unsigned int i=0; mensajeenblanco && i<mensaje.length(); i++) mensajeenblanco = (mensaje[i] == ' '); if (mensajeenblanco) { std::cout << "ERROR: Mensaje contiene solo espacios" << std::endl; // Comprobación- Los caracteres están en el alfabeto original int numerrores = 0; std::stringstream ss; for (unsigned int i=0; i<mensaje.length(); i++) if ( mensaje[i]!= ' ' && ( mensaje[i]< 'a' mensaje[i]> 'z' ) ) { numerrores++; ss << mensaje[i] << " "; if ( numerrores ) { std::cout << "ERROR: Mensaje contiene los " << numerrores << " siguientes caracteres no validos:\n" << ss.str() << std::endl; 10 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2018 // ------- // Cifrado // ------- std::stringstream ss_c; for (unsigned int i=0; i<mensaje.length(); i++) { if ( mensaje[i]!= ' ' ) { ss_c << alf_c[alf_m.find(mensaje[i])]; else { ss_c << " "; std::string cifrado = ss_c.str(); // ---------- // Descifrado // ---------- std::stringstream ss_d; for (unsigned int i=0; i<cifrado.length(); i++) { if ( cifrado[i]!= ' ' ) { ss_d << alf_m[alf_c.find(cifrado[i])]; else { ss_d << " "; std::string descifrado = ss_d.str(); // --------------------------------------- // Mostrar los tres mensajes en la consola // --------------------------------------- std::cout << "Mensaje original:\n" << mensaje << "\nmensaje cifrado:\n" << cifrado << "\nmensaje descifrado:\n" << descifrado << std::endl; // --------------------------------------------------- // Comprobar que mensaje original y descifrado iguales // --------------------------------------------------- if ( mensaje == cifrado ) { std::cout << "ERROR: original y descifrado no coinciden" << std::endl; else { std::cout << "Comprobacion OK" << std::endl; Dpto. de Informática y Automática, UNED 11
EJERCICIO 4 Consideremos el problema de calcular la temperatura que alcanza en el estacionario un punto situado en el centro de una región rectangular. La distribución de temperatura en el contorno de la región es conocida y se mantiene constante en el tiempo: la temperatura en uno de los lados largos es igual a 100 C y la temperatura en el resto del contorno es igual a 0 C. Para calcular la temperatura en el centro de la región rectangular, la recubrimos con una rejilla de celdas cuadradas iguales, empleando 2 N +1 celdas para cubrir el lado largo del rectángulo y 2 M + 1 el lado corto. De esta manera, una de las celdas contiene el centro de la región rectangular. En la figura se muestra un ejemplo, en el cual la región rectangular es cubierta por una rejilla de17 9 celdas (N = 8 y M = 4). El punto central, en el cual se quiere calcular la temperatura, está señalado en la figura. 0 100 C 0 0 C 0 0 C 0 0 C La evolución de la temperatura de las celdas se calcula comenzando en el instante de tiempo t 0 = 0 y avanzando a pasos en tiempo constantes. La temperatura de las celdas del contorno de la región rectangular se mantiene constante a los valores anteriormente indicados. Las temperaturas (T ) en el instante t i+1 de las celdas internas (celdas no pertenecientes al contorno de la región rectangular) se calculan promediando las temperaturas que sus ocho celdas vecinas tienen en el instante de tiempo anterior, t i, de la manera siguiente: T = 4 (N +S +E +O)+(NO +NE +SO+SE) 20 12 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2018 NO O N NE E SO S SE donde N, S, E, O, NO, NE, SO, SE son las temperaturas de las celdas vecinas en el instante de tiempot i. La nomenclatura empleada para nombrar a las celdas vecinas se muestra en la figura, donde pueden verse las 8 celdas vecinas de la celda sombreada. Escriba un programa en C++ que calcule la evolución de la temperatura en las celdas suponiendo que la región rectangular es cubierta por una rejilla de 201 101 celdas. Tome como condición inicial la siguiente. Todas las celdas de la rejilla, excepto las de la fila superior, se encuentran inicialmente a la temperatura0 C. Las celdas de la fila superior se encuentran inicialmente a 100 C. La condición de contorno es la siguiente. Las celdas de la fila superior se mantienen a una temperatura constante de 100 C, mientras que las restantes celdas del contorno se mantienen a una temperatura constante de 0 C. El programa debe calcular la temperatura de las celdas durante P = 50000 pasos en el tiempo, mostrando en la consola, cada p = 1000 pasos en el tiempo, la temperatura de la celda central de la región rectangular. Esto es, en los instantes t 0, t 1000, t 2000,..., t 50000. Muestre la temperatura en formato fijo, con 3 dígitos decimales. Dpto. de Informática y Automática, UNED 13
Solución al Ejercicio 4 #include<iostream> #include<iomanip> // Mallado - Filas: (2*M+1). Columnas: (2*N+1) const int N = 100; const int M = 50; // Condiciones iniciales const double Tini_sup = 100; const double Tini = 0; // Condición de finalización const int P = 50000; // Intervalo de comunicación const int p = 1000; int main() { const int Nfilas = 2*M+1; const int Ncols = 2*N+1; double T[Nfilas][Ncols]; // Inicialización for (unsigned int j=0; j<ncols; j++) T[0][j] = Tini_sup; for (unsigned int i=1; i<nfilas; i++) for (unsigned int j=0; j<ncols; j++) T[i][j] = Tini; // Simulación del autómata for (unsigned int t=0; t<=p; t++) { // Escritura en consola if ( t %p == 0 ) std::cout << "t = " << t << std::fixed << std::setprecision(3) << "\tt = " << T[M][N] << std::endl; // Cálculo temperaturas en t+1 double Taux[Nfilas][Ncols]; for (unsigned int i=1; i<(nfilas-1); i++) for (unsigned int j=1; j<(ncols-1); j++) Taux[i][j] = ( 4*( T[i-1][j] + T[i+1][j] + T[i][j+1] + T[i][j-1] ) + T[i-1][j-1] + T[i+1][j-1] + T[i-1][j+1] + T[i+1][j+1] ) / 20; for (unsigned int i=1; i<(nfilas-1); i++) for (unsigned int j=1; j<(ncols-1); j++) T[i][j] = Taux[i][j]; 14 Dpto. de Informática y Automática, UNED