Diferencia entre revisiones de «Práctica 3: Técnicas Algorítmicas (Algoritmos III)»
(No se muestran 38 ediciones intermedias de 12 usuarios) | |||
Línea 1: | Línea 1: | ||
==Ejercicio 03.01 | {{Back|Algoritmos y Estructuras de Datos III}} | ||
==Ejercicio 03.02:== | |||
==Ejercicio 03.01== | |||
Version recursiva | |||
<pre> | |||
int fib (n) | |||
si (n==0 || n==1) | |||
devolver n; | |||
sino | |||
devolver fib(n-1)+fib(n-2); | |||
</pre> | |||
Version no recursiva | |||
<pre> | |||
int fib (n) | |||
int mfib[n]; mfib[0] = 0; mfib[1] = 1; | |||
para i = 2..n | |||
mfib[i] = mfib[n-1]+mfib[n-2]; | |||
devolver mfib[n]; | |||
</pre> | |||
Complejidad temporal O(n), complejidad espacial O(n) | |||
Otra manera no recursiva | |||
<pre> | |||
int fib (n) | |||
if ( n <= 1 ) devolver 1 | |||
else | |||
int x = 1; | |||
int y = 1; | |||
para i = 2..n | |||
suma = x + y; | |||
y = x; | |||
x= suma; | |||
devolver suma | |||
</pre> | |||
Complejidad temporal O(n), complejidad espacial O(1) | |||
==Ejercicio 03.02== | |||
<br>a) Para mover n discos desde i hasta j usando k: | |||
<pre> | |||
Mover( inout i: Pila(nat), inout j: Pila(nat), inout k: Pila(nat), in n: nat ) | |||
Si n = 1 | |||
Apilar(tope(i),j) | |||
sino | |||
Mover(i, k, j, n-1) | |||
Mover(i, j, k, 1) | |||
Mover(k, j, i, n-1) | |||
</pre> | |||
<br>b) para demostrar la correctitud del algoritmo, lo podemos hacer por inducción basándonos que en n pasos nuestro algoritmo deja n-discos en la pila 3 de la forma correcta(es decir, el mas pesado debajo de todo y así con los de menor peso). | |||
CB: Muevo un disco de la pila 1 a la pila 3, vale. | |||
PI: Se asume que se dejaron n-1 discos correctamente ubicados en la pila 3, por lo que solo me queda mover un disco de la pila 1 a la 3, y como en esta ultima el orden era el correcto, vale para todo n. | |||
Lo importante a notar es que el algoritmmo mantiene invariante lo que realiza paso a paso, es decir, hace un montón de movimientos entre los distintos discos pero al final de cuentas los termina dejando acomodas en orden correcto en la pila3. | |||
<br>c) O(2^n) | |||
<br>d) Como son 64 discos, el número de movimientos es 2^64 - 1 = 18446744073709551615. Si suponemos que los monjes tienen la suficiente habilidad como para hacer un movimiento en un segundo, en un día harán 60*60*24 movimientos. Y en un año de 365 días: 60*60*24*365. Dividimos el número de movimientos por el resultado de la operación anterior y nos debe dar, aproximadamente, medio billón de años. Sólo falta averiguar cuantos años se estiman que el hombre lleva sobre la tierra y sabremos el tiempo que le queda sobre ella (TSUNAMI DE CHANES!!) | |||
==Ejercicio 03.03== | |||
<br>a) | <br>a) | ||
<pre> | |||
d_más_chica(Arreglo de puntos PS) | |||
Sort(PS,CoordX); | |||
si #PS = 2 | |||
devolver distancia(PS[1], PS[2]); | |||
sino | |||
dA = d_más_chica(P[1..n/2]); | |||
dB = d_más_chica(P[n/2+1..n]); | |||
dM = infinito | |||
para i=1..n/2 | |||
para j=n/2+1..n | |||
si d(P([i],P[j]) < dM | |||
dM = d(P([i],P[j]); | |||
devolver mínimo(dA, dB, dM); | |||
</pre> | |||
<br>b) | <br>b) | ||
<br>c) | <br>c) usando Teorema Maestro tenemos: T(n) = 2 * T(n/2) + n^2, que entra en el tercer caso, quedándonos: O(n^2) | ||
==Ejercicio 03. | ==Ejercicio 03.04== | ||
<br>a) | Codigo c++ | ||
<br>a) NOTA: Matriz es una clase que hice y que es muy larga como para poner aca. | |||
<pre> | |||
void aux_3_4(Matriz &fix, int d, int h, int dia) { | |||
if(h > d) { | |||
aux_3_4(fix, d, (d+h)/2, dia/2); | |||
aux_3_4(fix, (d+h)/2 + 1, h, dia/2); | |||
int i = d; | |||
int s = 0; | |||
while(i <= (d+h)/2){ | |||
int j = (d+h)/2 + 1; | |||
int c = s; | |||
while(j <= h){ | |||
fix.asignar(i, j, dia - abs(c) - 1); | |||
fix.asignar(j, i, dia - abs(c) - 1); | |||
j++; | |||
c++; | |||
} | |||
i++; | |||
s--; | |||
} | |||
} | |||
else | |||
fix.asignar(d, d, 0); //la diagonal se rellena de ceros | |||
} | |||
void ejercicio_3_4_a(Matriz &fixture, int n){ | |||
aux_3_4(fixture, 0, n-1, n); | |||
} | |||
</pre> | |||
<br>b) | <br>b) | ||
==Ejercicio 03. | ==Ejercicio 03.05== | ||
<br> | <br>i) NO. Contraejemplo: | ||
<br> | P1: s1=10, pi1=2 | ||
== | P2: s2=20, pi2= 8 | ||
Luego T = c*[2*10 + 8*(10 + 20)] = c*260 | |||
< | y si hubiesemos ordenado al reves, daria | ||
<br>iii) | c*[8*20 + 2*(20 + 10)] = c*220 < T | ||
==Ejercicio 03.06 | |||
<br>ii) NO. Contraejemplo: | |||
P1: pi1=2, s1=20 | |||
P2: pi2= 8, s2=10 | |||
Luego T = c*[2*20 + 8*(20 + 10)] = c*280 | |||
y si hubiesemos ordenado al reves, daria | |||
c*[8*10 + 2*(10 + 20)] = c*140 < T | |||
<br>iii) Funciona bien, pues lo ideal es s_i creciente y pi_i decreciente, entonces, pi_i/s_i decreciente | |||
==Ejercicio 03.06== | |||
<br>a) | <br>a) | ||
<br>Tomamos monedas de 25,10,5,1 | <br>Tomamos monedas de 25,10,5,1 | ||
Línea 45: | Línea 159: | ||
Conclusion: V = G | Conclusion: V = G | ||
<br>b) | <br>b) Si tomamos por ejemplo un vuelto de 15 centavos, el goloso nos daria el siguiente resultado: 15 = 1 moneda de 12 cent. + 3 de 1 cent, o sea 4 monedas. | ||
Usando otro criterio, y asumiendo que cuento con monedas de 10 y 5 centavos, puedo dar el vuelto con 2 monedas: 15 = 1 moneda 10 centavos + 5 centavos. | |||
Por lo tanto el criterio goloso no encuentra la solución óptima en este contexto. | |||
==Ejercicio 03.07== | |||
<br>a) Pseudocodigo | |||
<pre> | |||
Coef(n,k) | |||
si (calculado(n,k)) | |||
devolver mCoef[n,k]; | |||
si (k == 0 || k == n) | |||
res = 1; | |||
sino | |||
res = Coef(n-1, k-1) + Coef(n-1, k); | |||
mCoef[n,k] = res; | |||
devolver res; | |||
</pre> | |||
Codigo Cpp | |||
#include <iostream> | |||
#include <stdlib.h> | |||
#include <cstdio> | |||
using namespace std; | |||
void ej7(int n); | |||
void ej7(int n) | |||
{ | |||
int tabla[100][100]; | |||
//PROCESAR | |||
//O(n) | |||
for(int i = 0; i<n+1; i++) | |||
{ | |||
tabla[i][0] = 1; | |||
tabla[i][i+1] = 0; | |||
} | |||
//O(n) | |||
for(int i = 1; i<n+1; i++) | |||
{ | |||
//O(i) | |||
for(int j = 1; j<=i; j++) | |||
{ | |||
tabla[i][j] = tabla[i-1][j-1] + tabla[i-1][j]; | |||
} | |||
} | |||
//MOSTRAR RESULTADOS | |||
for(int i = 0; i<10; i++) { | |||
cout << endl; | |||
for(int j = 0; j<10; j++) | |||
cout << tabla[i][j] <<" "; | |||
} | |||
cout << endl; | |||
cout << endl; | |||
cout << "Resultado: "; | |||
for(int i = 0; i<n+1; i++) | |||
{ | |||
cout << tabla[n][i] <<" "; | |||
} | |||
} | |||
<br>b) O(n*k) | |||
<br>c) Se pueden usar 2 variables auxiliares con el fin de ir guardandome los calculos necesarios para calcular cada termino de fibonacci, hago un pseudocodigo: | |||
<pre> | |||
fibo(n) | |||
si n == 0 o n == 1, devolver 1 //caso base | |||
sino | |||
termino1 = 1, termino2 = 1 | |||
para i desde 2 hasta n, | |||
hacer: | |||
suma = termino1 + termino2; | |||
termino2 = termino1l; | |||
termino1 = suma; | |||
fin para | |||
devolver termino1; | |||
Como programación dinámica es botton up, voy construyendo la solución de menor termino hasta el n-esimo. | |||
</pre> | |||
==Ejercicio 03. | ==Ejercicio 03.08== | ||
<br>a) | <br>a) | ||
<br>b) | <pre> | ||
Nota: costo=int, pred: <int,int> | |||
camMinimo(int M[m][n]) | |||
Tupla<costo, pred> R[m][n]; | |||
Lista<int, int> camino; | |||
R(1,1)=< M[1,1], <0,0> >; | |||
R(f,1)=< Σ{i=1..f} M[i,1], <f-1,1> >; | |||
R(1,c)=< Σ{i=1..c} M[1,i], <1,c-1> >; | |||
para f=2..m | |||
para c=2..n | |||
si (R[f,c-1].costo < R[f-1,c].costo) | |||
R[f,c].costo = R[f,c-1].costo+M[f,c]; | |||
R[f,c].pred = <f,c-1>; | |||
sino | |||
R[f,c].costo = R[f-1,c].costo+M[f,c]; | |||
R[f,c].pred = <f-1,c>; | |||
res = R[m,n].costo; | |||
sig = <m,n>; | |||
mientras (R<sig>.pred != <0,0>) // reconstruyo camino | |||
camino = R<sig>.pred U camino; | |||
sig = R<sig>.pred; | |||
</pre> | |||
<br>b) O(m*n)tanto temporal como espacial. | |||
<br>c) | <br>c) | ||
==Ejercicio 03. | La matriz R seria: | ||
<br>a) | <pre> | ||
<br>b) | 2 10 13 17 | ||
< | 7 10 14 19 | ||
== | 8 10 12 13 | ||
< | 11 14 18 18 | ||
< | </pre> | ||
== | |||
==Ejercicio 03.11:== | ==Ejercicio 03.09== | ||
==Ejercicio 03.12 | <br>a) Primero pensemos en la funcion recursiva. TIP: veamos la version booleana y luego si sale, se puede hacer la version con los operandos. | ||
==Ejercicio 03.13 | |||
<br>a) | i es el indice del vector v de valores a los cuales se les van a aplicar los operandos. | ||
f(i,w) = { true si i=1 y W=v1 | |||
false si i = 1 y W !=v1 | |||
f(i-1,w-vi) || f(i-1, w/ri) || f(i-1, nroot(w)) //hacemos un or | |||
<br>b) Se puede ahcer pseudo-polinomial en O(nW) | |||
==Ejercicio 03.10== | |||
Codigo Cpp | |||
#include <iostream> | |||
#include <stdlib.h> | |||
#include <cstdio> | |||
using namespace std; | |||
enum ciudades {NY = 0, | |||
COL = 1, LOUIS = 2, NASH = 3, | |||
KANSAS = 4, OMAHA = 5, DALLAS = 6, | |||
SA = 7, DENVER = 8, | |||
LA = 9}; | |||
void ej10(); | |||
int dist (ciudades c1, ciudades c2); | |||
int dist (int c1, int c2); | |||
void ej10() | |||
{ | |||
//INICIALIZACION | |||
int tabla[10]; | |||
tabla[NY]= 0; | |||
// DIA 1 | |||
for (int i = 1; i<4; i++) | |||
tabla[i] = dist(NY, (ciudades)i); | |||
// DIA 2 | |||
for (int i = 4; i < 7; i++) | |||
{ | |||
int minDist = dist(i,1) + tabla[1]; | |||
for (int j = 2; j<4; j++) | |||
if (minDist > dist(i,j) + tabla[j]) | |||
minDist = dist(i,j) + tabla[j]; | |||
tabla[i] = minDist; | |||
} | |||
// DIA 3 | |||
for (int i = 7; i < 9; i++) | |||
{ | |||
int minDist = dist(i,4) + tabla[4]; | |||
for (int j = 5; j<7; j++) | |||
if (minDist > dist(i,j) + tabla[j]) | |||
minDist = dist(i,j) + tabla[j]; | |||
tabla[i] = minDist; | |||
} | |||
// DIA 4 | |||
tabla[9] = (dist(9,7) + tabla[7] < dist(9,8) + tabla[8]) | |||
? dist(9,7) + tabla[7] | |||
: dist(9,8) + tabla[8]; | |||
// MOSTRAR RESULTADOS | |||
for (int i = 0; i<10; i++) | |||
{ | |||
cout << endl << i << ": " << tabla[i]; | |||
} | |||
cout << endl << endl << "Valor final a LA: " << tabla[9] << endl; | |||
} | |||
int dist (int c1, int c2) | |||
{ | |||
return dist ((ciudades)c1, (ciudades)c2); | |||
} | |||
int dist (ciudades c1, ciudades c2) | |||
{ | |||
if (c1 > c2) | |||
{ | |||
ciudades aux; | |||
aux = c1; | |||
c1 = c2; | |||
c2 = aux; | |||
} | |||
else if (c1 == c2) | |||
{ | |||
return 0; | |||
} | |||
if (c1 == NY) | |||
{ | |||
switch (c2) | |||
{ | |||
case COL: return 550; | |||
case NASH: return 900; | |||
case LOUIS: return 770; | |||
default: | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
else if (c1 == COL) | |||
{ | |||
switch (c2) | |||
{ | |||
case KANSAS: return 680; | |||
case OMAHA: return 790; | |||
case DALLAS: return 1050; | |||
default: | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
else if (c1 == NASH) | |||
{ | |||
switch (c2) | |||
{ | |||
case KANSAS: return 580; | |||
case OMAHA: return 760; | |||
case DALLAS: return 660; | |||
default: | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
else if (c1 == LOUIS) | |||
{ | |||
switch (c2) | |||
{ | |||
case KANSAS: return 510; | |||
case OMAHA: return 700; | |||
case DALLAS: return 830; | |||
default: | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
else if (c1 == KANSAS) | |||
{ | |||
switch (c2) | |||
{ | |||
case DENVER: return 610; | |||
case SA: return 790; | |||
default: | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
else if (c1 == OMAHA) | |||
{ | |||
switch (c2) | |||
{ | |||
case DENVER: return 540; | |||
case SA: return 940; | |||
default: | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
else if (c1 == DALLAS) | |||
{ | |||
switch (c2) | |||
{ | |||
case DENVER: return 790; | |||
case SA: return 270; | |||
default: | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
else if (c1 == DENVER) | |||
{ | |||
switch (c2) | |||
{ | |||
case LA: return 1030; | |||
default: | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
else if (c1 == SA) | |||
{ | |||
switch (c2) | |||
{ | |||
case LA: return 1390; | |||
default: | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
else | |||
{ | |||
cout << "Error en dist: " << c1 << " y " << c2; | |||
return 0; | |||
} | |||
} | |||
==Ejercicio 03.11== | |||
Codigo Cpp | |||
#include <iostream> | |||
#include <stdlib.h> | |||
#include <cstdio> | |||
using namespace std; | |||
void ej11(); | |||
void ej11() | |||
{ | |||
// INICIALIZACIONES | |||
int costo[3] = {10*100, 10*100, 12*100}; | |||
int req[3] = {2, 5, 8}; | |||
int costoStock = 150; | |||
int costoInit = 250; | |||
int tablaCost[3][9]; | |||
int tablaPred[3][9]; | |||
for (int i = 0; i<3; i++) | |||
{ | |||
for (int j = 0; j < 9; j++) | |||
{ | |||
tablaCost[i][j] = 0; | |||
tablaPred[i][j] = 0; | |||
} | |||
} | |||
// PROCESO | |||
for (int mes = 0; mes < 3; mes++) | |||
{ | |||
for (int prod = req[mes]; prod < 9; prod++) | |||
{ | |||
if (mes == 0) | |||
{ | |||
tablaCost[mes][prod] = costo[mes] * prod + costoInit; | |||
} | |||
else | |||
{ | |||
int costoMin = (prod - req[mes-1]) * costoStock + tablaCost[mes-1][prod]; | |||
int pred = prod; | |||
// if (mes == 2) cout << "Stock mes anterior " << prod << "; costo " << costoMin << endl; | |||
for (int stock = req[mes-1]; stock < prod; stock++) | |||
{ | |||
int costoAct = (stock - req[mes-1])* costoStock; | |||
costoAct+= costo[mes] * (prod-stock) + costoInit; | |||
costoAct+= tablaCost[mes-1][stock]; | |||
// if (mes == 2) cout << "Mes " << mes << " a producir " << prod << ". Stock mes anterior " << stock << "; costo " << costoAct << endl; | |||
if (costoMin > costoAct) | |||
{ | |||
costoMin = costoAct; | |||
pred = stock; | |||
} | |||
} | |||
tablaCost[mes][prod] = costoMin; | |||
tablaPred[mes][prod] = pred; | |||
} | |||
} | |||
} | |||
// MOSTRAR RESULTADOS | |||
cout << endl << "Tabla de Prog Dinamica: " << endl; | |||
for(int i = 0; i<9; i++) { | |||
cout << endl; | |||
for(int j = 0; j<3; j++) | |||
cout << tablaCost[j][i] <<" "; | |||
} | |||
cout << endl << endl << "Tabla de Predecesores: " << endl; | |||
for(int i = 0; i<9; i++) { | |||
cout << endl; | |||
for(int j = 0; j<3; j++) | |||
cout << tablaPred[j][i] <<" "; | |||
} | |||
cout << endl << endl << "Resultado: " << tablaCost[2][8] << endl; | |||
cout << endl << "Esquema de produccion: " << endl; | |||
int mesAct = 2; | |||
int prodAct = 8; | |||
while (mesAct >= 0) | |||
{ | |||
// cout << "Prod Act " << prodAct; | |||
cout << "Mes " << mesAct +1 << " producir " << (prodAct - tablaPred[mesAct][prodAct]) * 100 << " unidades." << endl; | |||
prodAct = tablaPred[mesAct][prodAct]; | |||
mesAct--; | |||
} | |||
cout << endl; | |||
} | |||
==Ejercicio 03.12== | |||
==Ejercicio 03.13== | |||
<br>a) no es optimo ya que se puede realizar con solo 2 operaciones. Insertando una 'c' entre las 'b' y borrando la ultima 'a'. | |||
<br>b) | <br>b) | ||
<pre> | <pre> | ||
Línea 82: | Línea 606: | ||
<br>(Otro dia) | <br>(Otro dia) | ||
==Ejercicio 03.14 | ==Ejercicio 03.14== | ||
==Ejercicio 03.15 | ==Ejercicio 03.15== | ||
<br>a) | <br>a) | ||
<br>b) | <br>b) | ||
==Ejercicio 03.16 | ==Ejercicio 03.16== | ||
==Ejercicio 03.17 | ==Ejercicio 03.17== | ||
<br>a) | <br>a) | ||
<br>b) | <br>b) | ||
<br>c) | <br>c) | ||
==Ejercicio 03.18 | ==Ejercicio 03.18== | ||
<br>a) | <br>a) | ||
<br>b) | <br>b) | ||
<br>c) | <br>c) | ||
==Ejercicio 03.19 | ==Ejercicio 03.19== | ||
[[Category: Prácticas]] |
Revisión actual - 21:22 4 may 2020
Ejercicio 03.01
Version recursiva
int fib (n) si (n==0 || n==1) devolver n; sino devolver fib(n-1)+fib(n-2);
Version no recursiva
int fib (n) int mfib[n]; mfib[0] = 0; mfib[1] = 1; para i = 2..n mfib[i] = mfib[n-1]+mfib[n-2]; devolver mfib[n];
Complejidad temporal O(n), complejidad espacial O(n)
Otra manera no recursiva
int fib (n) if ( n <= 1 ) devolver 1 else int x = 1; int y = 1; para i = 2..n suma = x + y; y = x; x= suma; devolver suma
Complejidad temporal O(n), complejidad espacial O(1)
Ejercicio 03.02
a) Para mover n discos desde i hasta j usando k:
Mover( inout i: Pila(nat), inout j: Pila(nat), inout k: Pila(nat), in n: nat ) Si n = 1 Apilar(tope(i),j) sino Mover(i, k, j, n-1) Mover(i, j, k, 1) Mover(k, j, i, n-1)
b) para demostrar la correctitud del algoritmo, lo podemos hacer por inducción basándonos que en n pasos nuestro algoritmo deja n-discos en la pila 3 de la forma correcta(es decir, el mas pesado debajo de todo y así con los de menor peso).
CB: Muevo un disco de la pila 1 a la pila 3, vale.
PI: Se asume que se dejaron n-1 discos correctamente ubicados en la pila 3, por lo que solo me queda mover un disco de la pila 1 a la 3, y como en esta ultima el orden era el correcto, vale para todo n.
Lo importante a notar es que el algoritmmo mantiene invariante lo que realiza paso a paso, es decir, hace un montón de movimientos entre los distintos discos pero al final de cuentas los termina dejando acomodas en orden correcto en la pila3.
c) O(2^n)
d) Como son 64 discos, el número de movimientos es 2^64 - 1 = 18446744073709551615. Si suponemos que los monjes tienen la suficiente habilidad como para hacer un movimiento en un segundo, en un día harán 60*60*24 movimientos. Y en un año de 365 días: 60*60*24*365. Dividimos el número de movimientos por el resultado de la operación anterior y nos debe dar, aproximadamente, medio billón de años. Sólo falta averiguar cuantos años se estiman que el hombre lleva sobre la tierra y sabremos el tiempo que le queda sobre ella (TSUNAMI DE CHANES!!)
Ejercicio 03.03
a)
d_más_chica(Arreglo de puntos PS) Sort(PS,CoordX); si #PS = 2 devolver distancia(PS[1], PS[2]); sino dA = d_más_chica(P[1..n/2]); dB = d_más_chica(P[n/2+1..n]); dM = infinito para i=1..n/2 para j=n/2+1..n si d(P([i],P[j]) < dM dM = d(P([i],P[j]); devolver mínimo(dA, dB, dM);
b)
c) usando Teorema Maestro tenemos: T(n) = 2 * T(n/2) + n^2, que entra en el tercer caso, quedándonos: O(n^2)
Ejercicio 03.04
Codigo c++
a) NOTA: Matriz es una clase que hice y que es muy larga como para poner aca.
void aux_3_4(Matriz &fix, int d, int h, int dia) { if(h > d) { aux_3_4(fix, d, (d+h)/2, dia/2); aux_3_4(fix, (d+h)/2 + 1, h, dia/2); int i = d; int s = 0; while(i <= (d+h)/2){ int j = (d+h)/2 + 1; int c = s; while(j <= h){ fix.asignar(i, j, dia - abs(c) - 1); fix.asignar(j, i, dia - abs(c) - 1); j++; c++; } i++; s--; } } else fix.asignar(d, d, 0); //la diagonal se rellena de ceros } void ejercicio_3_4_a(Matriz &fixture, int n){ aux_3_4(fixture, 0, n-1, n); }
b)
Ejercicio 03.05
i) NO. Contraejemplo:
P1: s1=10, pi1=2 P2: s2=20, pi2= 8
Luego T = c*[2*10 + 8*(10 + 20)] = c*260 y si hubiesemos ordenado al reves, daria c*[8*20 + 2*(20 + 10)] = c*220 < T
ii) NO. Contraejemplo:
P1: pi1=2, s1=20 P2: pi2= 8, s2=10
Luego T = c*[2*20 + 8*(20 + 10)] = c*280 y si hubiesemos ordenado al reves, daria c*[8*10 + 2*(10 + 20)] = c*140 < T
iii) Funciona bien, pues lo ideal es s_i creciente y pi_i decreciente, entonces, pi_i/s_i decreciente
Ejercicio 03.06
a)
Tomamos monedas de 25,10,5,1
Sol. Optima V = (v1,v2,..,vn) / v1 >= v2 >= .. >= vn
Sol. Optima G = (g1,g2,..,gn) / g1 >= g2 >= .. >= gn
qvq Sol. del Goloso G = V
Puede Pasar (G inc V) o (V inc G)? NO (suma de G = suma de V)
Vj < Gj (sino el goloso lo hubiera elegido)
Gj > Vj >= Vj+1 >= ... >= Vm
Ex. j / Vj != Gj Vi = Gi i<j
Gj | 25 | 10 | 5 |
---|---|---|---|
Vj | 10,5,1 | 5,1 | 1 |
1) Vj = 1 -> Vj+1 .. Vm
No puede ocurrir porque la suma tenia que ser la misma, tampoco puede haber un 10 o 5
2) Vj = 5
No puedo tener otro 5 (para eso pongo un 5), tampoco puede haber un 25 en Gj
3) Vj = 10
Tampoco, ya que 10,10,5 no seria optimo
Conclusion: V = G
b) Si tomamos por ejemplo un vuelto de 15 centavos, el goloso nos daria el siguiente resultado: 15 = 1 moneda de 12 cent. + 3 de 1 cent, o sea 4 monedas.
Usando otro criterio, y asumiendo que cuento con monedas de 10 y 5 centavos, puedo dar el vuelto con 2 monedas: 15 = 1 moneda 10 centavos + 5 centavos.
Por lo tanto el criterio goloso no encuentra la solución óptima en este contexto.
Ejercicio 03.07
a) Pseudocodigo
Coef(n,k) si (calculado(n,k)) devolver mCoef[n,k]; si (k == 0 || k == n) res = 1; sino res = Coef(n-1, k-1) + Coef(n-1, k); mCoef[n,k] = res; devolver res;
Codigo Cpp
#include <iostream> #include <stdlib.h> #include <cstdio> using namespace std; void ej7(int n); void ej7(int n) { int tabla[100][100]; //PROCESAR //O(n) for(int i = 0; i<n+1; i++) { tabla[i][0] = 1; tabla[i][i+1] = 0; } //O(n) for(int i = 1; i<n+1; i++) { //O(i) for(int j = 1; j<=i; j++) { tabla[i][j] = tabla[i-1][j-1] + tabla[i-1][j]; } } //MOSTRAR RESULTADOS for(int i = 0; i<10; i++) { cout << endl; for(int j = 0; j<10; j++) cout << tabla[i][j] <<" "; } cout << endl; cout << endl; cout << "Resultado: "; for(int i = 0; i<n+1; i++) { cout << tabla[n][i] <<" "; } }
b) O(n*k)
c) Se pueden usar 2 variables auxiliares con el fin de ir guardandome los calculos necesarios para calcular cada termino de fibonacci, hago un pseudocodigo:
fibo(n) si n == 0 o n == 1, devolver 1 //caso base sino termino1 = 1, termino2 = 1 para i desde 2 hasta n, hacer: suma = termino1 + termino2; termino2 = termino1l; termino1 = suma; fin para devolver termino1; Como programación dinámica es botton up, voy construyendo la solución de menor termino hasta el n-esimo.
Ejercicio 03.08
a)
Nota: costo=int, pred: <int,int> camMinimo(int M[m][n]) Tupla<costo, pred> R[m][n]; Lista<int, int> camino; R(1,1)=< M[1,1], <0,0> >; R(f,1)=< Σ{i=1..f} M[i,1], <f-1,1> >; R(1,c)=< Σ{i=1..c} M[1,i], <1,c-1> >; para f=2..m para c=2..n si (R[f,c-1].costo < R[f-1,c].costo) R[f,c].costo = R[f,c-1].costo+M[f,c]; R[f,c].pred = <f,c-1>; sino R[f,c].costo = R[f-1,c].costo+M[f,c]; R[f,c].pred = <f-1,c>; res = R[m,n].costo; sig = <m,n>; mientras (R<sig>.pred != <0,0>) // reconstruyo camino camino = R<sig>.pred U camino; sig = R<sig>.pred;
b) O(m*n)tanto temporal como espacial.
c)
La matriz R seria:
2 10 13 17 7 10 14 19 8 10 12 13 11 14 18 18
Ejercicio 03.09
a) Primero pensemos en la funcion recursiva. TIP: veamos la version booleana y luego si sale, se puede hacer la version con los operandos.
i es el indice del vector v de valores a los cuales se les van a aplicar los operandos.
f(i,w) = { true si i=1 y W=v1
false si i = 1 y W !=v1 f(i-1,w-vi) || f(i-1, w/ri) || f(i-1, nroot(w)) //hacemos un or
b) Se puede ahcer pseudo-polinomial en O(nW)
Ejercicio 03.10
Codigo Cpp
#include <iostream> #include <stdlib.h> #include <cstdio> using namespace std; enum ciudades {NY = 0, COL = 1, LOUIS = 2, NASH = 3, KANSAS = 4, OMAHA = 5, DALLAS = 6, SA = 7, DENVER = 8, LA = 9}; void ej10(); int dist (ciudades c1, ciudades c2); int dist (int c1, int c2); void ej10() { //INICIALIZACION int tabla[10]; tabla[NY]= 0; // DIA 1 for (int i = 1; i<4; i++) tabla[i] = dist(NY, (ciudades)i); // DIA 2 for (int i = 4; i < 7; i++) { int minDist = dist(i,1) + tabla[1]; for (int j = 2; j<4; j++) if (minDist > dist(i,j) + tabla[j]) minDist = dist(i,j) + tabla[j]; tabla[i] = minDist; } // DIA 3 for (int i = 7; i < 9; i++) { int minDist = dist(i,4) + tabla[4]; for (int j = 5; j<7; j++) if (minDist > dist(i,j) + tabla[j]) minDist = dist(i,j) + tabla[j]; tabla[i] = minDist; } // DIA 4 tabla[9] = (dist(9,7) + tabla[7] < dist(9,8) + tabla[8]) ? dist(9,7) + tabla[7] : dist(9,8) + tabla[8]; // MOSTRAR RESULTADOS for (int i = 0; i<10; i++) { cout << endl << i << ": " << tabla[i]; } cout << endl << endl << "Valor final a LA: " << tabla[9] << endl; } int dist (int c1, int c2) { return dist ((ciudades)c1, (ciudades)c2); } int dist (ciudades c1, ciudades c2) { if (c1 > c2) { ciudades aux; aux = c1; c1 = c2; c2 = aux; } else if (c1 == c2) { return 0; } if (c1 == NY) { switch (c2) { case COL: return 550; case NASH: return 900; case LOUIS: return 770; default: cout << "Error en dist: " << c1 << " y " << c2; return 0; } } else if (c1 == COL) { switch (c2) { case KANSAS: return 680; case OMAHA: return 790; case DALLAS: return 1050; default: cout << "Error en dist: " << c1 << " y " << c2; return 0; } } else if (c1 == NASH) { switch (c2) { case KANSAS: return 580; case OMAHA: return 760; case DALLAS: return 660; default: cout << "Error en dist: " << c1 << " y " << c2; return 0; } } else if (c1 == LOUIS) { switch (c2) { case KANSAS: return 510; case OMAHA: return 700; case DALLAS: return 830; default: cout << "Error en dist: " << c1 << " y " << c2; return 0; } } else if (c1 == KANSAS) { switch (c2) { case DENVER: return 610; case SA: return 790; default: cout << "Error en dist: " << c1 << " y " << c2; return 0; } } else if (c1 == OMAHA) { switch (c2) { case DENVER: return 540; case SA: return 940; default: cout << "Error en dist: " << c1 << " y " << c2; return 0; } } else if (c1 == DALLAS) { switch (c2) { case DENVER: return 790; case SA: return 270; default: cout << "Error en dist: " << c1 << " y " << c2; return 0; } } else if (c1 == DENVER) { switch (c2) { case LA: return 1030; default: cout << "Error en dist: " << c1 << " y " << c2; return 0; } } else if (c1 == SA) { switch (c2) { case LA: return 1390; default: cout << "Error en dist: " << c1 << " y " << c2; return 0; } } else { cout << "Error en dist: " << c1 << " y " << c2; return 0; } }
Ejercicio 03.11
Codigo Cpp
#include <iostream> #include <stdlib.h> #include <cstdio> using namespace std; void ej11(); void ej11() { // INICIALIZACIONES int costo[3] = {10*100, 10*100, 12*100}; int req[3] = {2, 5, 8}; int costoStock = 150; int costoInit = 250; int tablaCost[3][9]; int tablaPred[3][9]; for (int i = 0; i<3; i++) { for (int j = 0; j < 9; j++) { tablaCost[i][j] = 0; tablaPred[i][j] = 0; } } // PROCESO for (int mes = 0; mes < 3; mes++) { for (int prod = req[mes]; prod < 9; prod++) { if (mes == 0) { tablaCost[mes][prod] = costo[mes] * prod + costoInit; } else { int costoMin = (prod - req[mes-1]) * costoStock + tablaCost[mes-1][prod]; int pred = prod; // if (mes == 2) cout << "Stock mes anterior " << prod << "; costo " << costoMin << endl; for (int stock = req[mes-1]; stock < prod; stock++) { int costoAct = (stock - req[mes-1])* costoStock; costoAct+= costo[mes] * (prod-stock) + costoInit; costoAct+= tablaCost[mes-1][stock]; // if (mes == 2) cout << "Mes " << mes << " a producir " << prod << ". Stock mes anterior " << stock << "; costo " << costoAct << endl; if (costoMin > costoAct) { costoMin = costoAct; pred = stock; } } tablaCost[mes][prod] = costoMin; tablaPred[mes][prod] = pred; } } } // MOSTRAR RESULTADOS cout << endl << "Tabla de Prog Dinamica: " << endl; for(int i = 0; i<9; i++) { cout << endl; for(int j = 0; j<3; j++) cout << tablaCost[j][i] <<" "; } cout << endl << endl << "Tabla de Predecesores: " << endl; for(int i = 0; i<9; i++) { cout << endl; for(int j = 0; j<3; j++) cout << tablaPred[j][i] <<" "; } cout << endl << endl << "Resultado: " << tablaCost[2][8] << endl; cout << endl << "Esquema de produccion: " << endl; int mesAct = 2; int prodAct = 8; while (mesAct >= 0) { // cout << "Prod Act " << prodAct; cout << "Mes " << mesAct +1 << " producir " << (prodAct - tablaPred[mesAct][prodAct]) * 100 << " unidades." << endl; prodAct = tablaPred[mesAct][prodAct]; mesAct--; } cout << endl; }
Ejercicio 03.12
Ejercicio 03.13
a) no es optimo ya que se puede realizar con solo 2 operaciones. Insertando una 'c' entre las 'b' y borrando la ultima 'a'.
b)
dist("",v[1..m]) = m dist(u[1..n],"") = n dist(u[1..n],v[1..m]) = min (1+dist(u[1..n],v[1..m-1]), (insertar Vm) 1+dist(u[1..n-1],v[1..m]), (borrar Vm) if u[n]=v[m] then 0 else 1+ dist(u[1..n-1],v[1..m-1]) (cambiar/nada con Vm) )
Algoritmo:
M[0,j] = j
M[i,0] = i
M[i,j] = dist(u[1..i],v[1..j]) = min ( 1+M[i,j-1], .. )
Correctitud:
(Otro dia)
Ejercicio 03.14
Ejercicio 03.15
a)
b)
Ejercicio 03.16
Ejercicio 03.17
a)
b)
c)
Ejercicio 03.18
a)
b)
c)