View
575
Download
1
Embed Size (px)
Citation preview
ANALISIS DE ALGORITMO Y COMPLEJIDAD COMPUTACIONAL
The Game Chess
Cuantos granos de trigo son? si en cada cuadrado del tablero se dobla la cantidad anterior:
63
Σ2i = 264 – 20 = 1,8*1019
i=0
Teoría de Algoritmos Análisis y Complejidad
Teoría Complejidad Computacional = El estudio de resolver problemas interesantes
Medida de la cantidad de recursos necesarios:espaciotiempo
Sobre los algoritmos:
Polinomio es Bueno --------- Entre más pequeño mejor
Exponencial es malo --------- Entre más pequeño mejor
Para que estudiar este Tema:
Eficientes algoritmos llevan a eficientes programas
Programas eficientes se venden mejorProgramas eficientes hacen un mejor uso del hardwareProgramadores que escriben mejores programas son más requeridos
Factores Influyen en la Eficiencia de Programas:Problema a resolver.
Lenguaje de programación.CompiladorHardwareHabilidad del programadorEficacia del programadorAlgoritmo
Algoritmos CorregidosProblema a resolver.
Lenguaje de programación.CompiladorHardwareHabilidad del programadorEficacia del programadorAlgoritmo
Resumen
Confianza en los algoritmo desde las pruebas y pruebas corregidas
Corregir algoritmos recursivos probar directamente por inducción
Corregir algoritmos iterativos usando loop invariantes e inducción
Correcciones
Confianza en los algoritmo desde las pruebas y pruebas corregidas
Corregir algoritmos recursivos probar directamente por inducción
Corregir algoritmos iterativos usando loop invariantes e inducción
Correcciones
Lógico Método de Corregir Chequeando
TestingPruebas Corregidas
Testing versus Pruebas Corregidas
Testing : Trata algoritmo son una entrada de ejemplo.
Prueba Corregida : Prueba matemáticamentePuede no encontrar problemas
Testing : Puede no encontrar problemas: Usar test solo puede ser peligroso
Usar una combinación de ambas es mejor
Correcciones de Algoritmos Recursivos
Para probar correcciones de algoritmos recursivos:
Probar por inducción el tamaño del problema a ser resuelto.
Base recursividad, es la base de la inducción
Necesita probar que llamadas recursivas, no son infinitas recursividades
Paso inductivo: Asumo que la recursividad llama correctamente, así pruebo que trabaja correctamente.
Número Recursivo Fibonacci
Número Fibonacci:
F0 = 0F1 = 1
y para todo 2 ≤ n, Fn = Fn-2 + Fn-1
function fib(n)comment return FnIf n ≤ 1 then return(n)else return(fib(n-1) + fib(n-2))
Reivindica: Para todo n ≥ 0, fib(n) return Fn
Base :Para n = 0, fib(n) retorna 0, está reivindicadoPara n = 1, fib(n) retorna 1, está reivindicado
Inducción:Supuesto que n ≥ 2, y para todo 0 ≤ m ≤ n, fib(m) retorna FmSupuesto fin(n) retorna Fn
Así :fib(n) = fib(n-1) + fib(n-2)
FibonacciInt fibonacci(int n)
if ((n==0) II (n==1))return n;
elsereturn fibonacci(n-1) + fibonacci(n-2);
T(n) = O(1) si ≤ 1T(n) = T(n-1) + T(n-2) + 1 si n > 1
AnálisisLa operación básica que se hace es la suma, se define C(n) como la cantidad de sumas necesarias para calcular fibonacci(n).
Si a C(0),C(1),…,(Cn)… es claro que C0 = 0 y C1 = 0
y para n ≥ 2, es Cn = Cn-1 + Cn-2 + 1
Su generatriz es: C(z) = Σ CnZn n≥o
Σn≥oCnZn = Σn≥2(Cn-1 + Cn-2 + 1)Zn
Σn≥oCnZn = Σn≥2(Cn-1 + Cn-2 + 1)Zn
Transformando generatrices a otras conocidas. Primero se separa en tres sumatorias.
Luego se ajustan los índices
Se sacan factores
Como C0 = 0, entonces , sumando y restando 1 + Z
Ahora como y resulta que
Simplificando
Las raíces del polinomio son
Siendo y su conjugado
Por lo que se puede factorizar
comúnmente conocido como razón aurea
Aplicando la propiedad se llega a
Por lo que llegamos a que
Lo que descomponemos en
igualando coeficientes resulta que
operando
sistemas de ecuaciones
Los valores son:
Por lo que la función generatriz queda:
Extrayendo coeficientes:
Como el módulo de es inferior a uno asintóticamente se comporta
Así, se concluye que, fibonacci es de orden: O(
ANALISIS DE ALGORITMO
Implementando Algoritmos
Gran O(h)
Definición:
f(n) es del orden de g(n), f(n) = O(g(n)), si existe c, no Є R+ tal que ara todo n ≥ no,
f(n) ≤ cg(n)
Ejemplo:
log(n) es O(n)
Reivindica: Para todo n ≥ 1, log(n) ≤ n.
Se prueba por inducción:
La reivindicación es trivial para n=1. dado que log(1) = 0 < 1.
Ahora se supone cierto para n ≥ 1 y log(n) ≤ n.
Entonces:log(n+1)
≤ log(2n)= logn +1≤ n + 1 (por hipótesis de inducción)
Gran Ω(h)
Definición:
f(n) es del orden de g(n), f(n) = Ω(g(n)), si existe c > 0, tales que son muchos infinitamente n Є N tal que,
f(n) ≥ cg(n)
Gran Ω’(h)
Definición:
f(n) es del orden de g(n), f(n) = Ω’(g(n)), si existe c,n0 Є R+> 0, tales que para todo n ≥ n0,
f(n) ≥ cg(n)
Es esta una Diferencia
Si f(n) = Ω’(g(n)), f(n) = Ω(g(n)) la inversa no es cierta. Por ejemplo.
Gran Ѳ(h)
Definición:
f(n) es Ѳ (g(n)), sí y solo sí f(n) es O(g(n)) y f(n) es Ω(g(n))
Sumando O(h)
Si f1(n) es O(g1(n)) y f2(n) es O(g2(n)) f1(n) + f2(n) es O(g1(n) + g2(n))
Multiplicando O(h)
Si f1(n) es O(g1(n)) y f2(n) es O(g2(n)) f1(n) f2(n) es O(g1(n)*g2(n))
Tipo de Análisis
Peor Caso: El tiempo que toma en el peor caso posible. Es el máximo T(n) sobre una entrada de tamaño n.
Caso Promedio: Es la expectativa de tiempo corriendo, dada alguna probabilidad o distribución de tiempo (usualmente uniforme). T(n) es el tiempo que toma sobre toda entrada de tamaño n en promedio.
Caso Probabilístico: Es la expectativa de tiempo que corre sobre una rango de entradas posibles.
Caso Amortizado: El tiempo de corrida pata una serie de ejecuciones, dividida por el número de ejecuciones.
Complejidad Tiempo
Analizando los tiempos en el peor caso:asignación O(1)procedimiento entrada O(1)procedimiento salida O(1)si el test hay dos ramas O(máximo de las dos ramas)loop suma sobre todas las iteraciones del
tiempo de cada iteración.
Multiplicación
function multiply(y,z)comment Return yz, donde y,z Є IN
1. x:= 0;2. while z>0 do3. if z is odd then x:= x + y;4. y:=2y; z:=(z/2);5. return(x)
Supuesto y y z tienen n bits.
procedimiento de entrada y salida costo O(1) veceslineas 3,4 costo O(1) cada vezel while loop sobre límeas 2-4 costos O(n) veces (es ejecutada a lo más n veces)línea 1 costos O(1) veces
Entonces, la multiplicación toma O(n) veces
Bubblesort
1. procudere bubblesort(A[1..n])2. for i:=1 to n-1 do3. for j:=0 to n-i do4. if A[j] > A[j+1] then5. Swap A[j] with A[j+1]
procedimiento de entrada y salida costo O(1) veceslínea 5costo O(1) cada vezel if de la sentencia de líneas 4-5 costosO(1)El for-loop sobre líneas 3-5 costos O(n-i) vecesEl for-loop sobre líneas 2-5 costos O( )
El bubblesort toma tiempo de O(n2) en el peor caso.
Análisis de Algoritmos Iterativos (no recursivos)
El Heap: Una implementación de prioridad de la cola
•Tiempo de inserción O(log(n))•Tiempo de borrado O(log(n))
Heapsort
• Construir un Heap O(nlog(n))• Deshacer un Heap O(nlog(n))• Análisis peor caso O(nlog(n))•Como construir un Heap en O(n)
HeapEl Heap: es una popular implementación. Un heap es un árbol binario con los datos cargados en los nodos, Tiene dos importantes propiedades.
1. Balance. Completar el árbol binario sin pérdida de hojas, en los últimos niveles del lado izquierdo.
2. El valor de las hoja del padre es menor que el valor de las hojas del hijo.
Borrar el MínimoBorrarlo de la raíz, y devolver el valor.
Pero lo que se tiene ya no es un árbol!!!
Reemplazar la raíz por la última hoja.
Pero se viola la condición de la estructura!!!
Reemplazar la raíz por la última hoja.
Pero se viola la condición de la estructura!!!
Repetidamente cambiar el elemento hijo más pequeño.
Como esto TrabajaPor qué el intercambio del nuevo nodo es el hijo más pequeño?
o
Supuesto b ≤ c y a no está en el lugar correcto. Esto es a>b o a>c . En este caso b ≤ c, nosotros sabemos que a > b.
o
Lo que lleva a:
o
respectivamente.Si b es más pequeño que sus hijos? Si, porque b < c y b ≤ c.
Si b es más pequeño que sus hijos? Si, porque b < c y b ≤ c.
C es el más pequeño de estos hijos? Si, porque se verificó antes.
Es a más pequeño que éstos hijos? No necesariamente, así puede continuar intercambiándose y bajando por el árbol.
El sub árbol de c, tiene la condición de estructura? Si, dado que esto no ha cambiado.
Insertar un nuevo Elemento
Preservando balance
Implementando un Heap
Un heap de n nodos usados en un arreglo A[1..n]
* La raíz está cargada con A[1]* Los hijos a la izquierda de un nodo en A[i] está cargada en nodo A[2i]* Los hijos a la derecha de un nodo A[i] está cargada en nodo A[2i+1]
Implementando un Heap
Un heap de n nodos usados en un arreglo A[1..n]
* La raíz está cargada con A[1]* Los hijos a la izquierda de un nodo en A[i] está cargada en nodo A[2i]* Los hijos a la derecha de un nodo A[i] está cargada en nodo A[2i+1]
Borrar el Mínimo
Remover raíz O(1)Reemplazar raíz O(1)Swaps O(l(n))
Donde l(n) es el número de niveles en n-nodo heap.
Insertar
Poner una hoja O(1)Swaps O(l(n))
Análisis de l(n)
Un árbol binario completo con k niveles, tiene exactamente 2k-1 nodos. Entonces con k niveles tiene no menos 2k-1 y no más que 2k-1 .
Entonces en un heap con k niveles y n nodos:
Resumen
Análisis de algoritmos recursivos:
* relación de recurrencia* como deriva* como se soluciona
Derivando la Relación de Recurrencia
Para encontrar la relación de recurrencia corriendo veces a un algoritmo:
* n es el tamaño del problema* ver que valor de n es usado sobre la base recursividad* Ver el valor de T(no), usualmente una constante* Usualmente en la recursividad un problema de tamaño f)n) da un término a*T(f(n)) en la
relación de recursividad.
Derivando la Relación de Recurrencia
Para encontrar la relación de recurrencia corriendo veces a un algoritmo:
* n es el tamaño del problema* ver que valor de n es usado sobre la base recursividad* Ver el valor de T(no), usualmente una constante* Usualmente en la recursividad un problema de tamaño f)n) da un término a*T(f(n)) en la
relación de recursividad.
Derivando la Relación de Recurrencia
Derivando la Relación de Recurrencia
Ejemplos:
Así, T(n) el tiempo para multiply(y,z), donde z es un n-bits número natural.
Entonces para algún c,d Є IR
T(n) = c si n=1T(n-1) + d en otro caso
Resolviendo la relación de recurrencia:
Se sabe que: T(n) = T(n-1) + d para todo n> 1
Entonces, para una gran cantidad de n
T(n) = T(n-1) + dT(n-1) = T(n-2) + dT(n-2) = T(n-3) + d
.
.T(2) = T(1) + dT(1) = c
= T(n-1) +d= T((n-2)+d)+d= (T(n-3)+d)+2d= T(n-3)+3f..= T(n-i)+id
Si i=n-1T(n) = dn +c –d
Esto no es una prueba, es una secuencia lógica.
Hay que hacer inducción sobre i o sobre n.
Reivindicación: T(n) = dn +c –d, prueba por inducción sobre n.
Para n = 1 T(n) = d+c-d = c
Supuesto verdad por hipótesis sobre n,
Ahora:
T(n+1) = T(n)+d(dn + c –d) + d (hipótesis de inducción)dn + c
Teorema General
Si n es una potencia de c, la solución para la recurrencia:
T(n) = d si n ≤ 1aT(n/c) +bn en otro caso
O(n) si a<cT(n) = O(nlogn) si a=c
O(nlogca) si a>c
Dividir y Reinar
Para solucionar un problema:
* Dividir dentro de pequeños problemas* Solucionar el pequeño problema* Combinar las soluciones y ponerlas dentro del gran problema
Encontrar el Máximo y el MínimoEncontrar el máximo y mínimo se un arreglo S[1..n]. Cuántas comparaciones entre los elementos de S se necesitan?
Max n
Min n-1
Total 2n-1
Multiplicación de Matrices
Asume que toda operación de enteros toma O(1) tiempo: El algoritmo de mutiplicaciòn de matriz ingenua toma O(n3). Se puede mejorar?
Dividir para Reinar
Dividir X,Y,Z cada uno en cuatro de (n/2)*(n/2) matrices
Entonces:
Así, T(n) es el tiempo de multiplicar 2 n*n matrices.La aproximación está dada por:
Si n= 1otro caso
c, d constantes
Entonces:T(n) = 8T(n/2) + dn2
8(8T(n/4) +d(n/2)2) +dn2
82*T(n/4) + 2dn2 + dn2
83*T(n/8) + 4dn2 + 2dn2 + dn2
i-1
8iT(n/2i) + dn2Σ2j
j=0
logn-1
8lognT(1) + dn2 Σ2j
j=0
cn3 + dn2(n-1)O(n3)
Algoritmo de Strassen
Cálculo
Entonces
Esto es:
Esto es:
Análisis del algoritmo de Strassen
PROGRAMACION DINAMICA
Dividir para reinar con una tabla:
CombinatoriaProblemas de Knapsack
Contando Combinaciones
Elige r desde n, a su
•Elegir el primer items. Así elegir el remanente r-1 items desde n-1.• No elegir el primer item. Entonces se debe elegir r entre los n-1
Así:
PROGRAMACION DINAMICA
Dividir para reinar con una tabla:
CombinatoriaProblemas de Knapsack
Contando Combinaciones
Elige r desde n, a su
•Elegir el primer items. Así elegir el remanente r-1 items desde n-1.• No elegir el primer item. Entonces se debe elegir r entre los n-1
Así:
ALGORITMO PARA RESOLVER
Probar por InducciónAnálisis
Entonces:
Análisis:
Ejemplo:
Repiten cálculos
Un mejor Algoritmo: Tabla Pascal
Inicialización
Regla General
Para llenar T[i,j] = T[i-1,j-1] + T[i-1,j]
Se llena la tabla, de arriba a bajo de la siguiente manera:
Análisis Algoritmo
Cuanto toma llenar la tabla.
(n-r+1)(r+1) = nr + n – r2 + 1 ≤ n(r + 1) +1
Cada entrada toma O(1) el total requerido es O(n2) es mejor que O(2n)
Programación Dinámica
Cuando se subdivide para reinar, se generan un número importante de problemas idénticos, luego la recursión también se pude mejorar. Luego la solución es una tabla.
La técnica es llamada programación dinámica.
Técnica de Programación Dinámica
Para diseñar un algoritmo de programación dinámica:
Identificar:
* Algoritmo de dividir y reinar* Analizar si el tiempo del algoritmo es exponencial.• Algunos sub – problemas son resueltos muchas veces.• Hay que identificar del algoritmo la parte a dividir y la parte recursiva•Registrar tabla de entrada•Usar la base de dividir para reinar para llenar la tabla.•Ver como queda y usarla.
En el caso del Ejemplo:
Grafos
Un grafo es un par ordenado G = (V,E)
V es un conjunto finito de vérticesE C VxV es un conjunto de arcos
Por Ejemplo:
V = 1,2,3,4,5
E = (1,2),(1,4),(1,5),(2,3),(3,4),(3,5),(4,5)
Grafo Dirigido
Un grafo dirigido es un grafo con direcciones sobre los arcos.
Por ejemplo:
Rotulado Grafo Dirigido
Un grafo dirigido es un grafo con direcciones sobre los arcos y costos positivos sobre los costos.
Aplicaciones:Ciudades y distancias de camino.Costos de producción asociados a un proceso.
Convención:n es el número de vérticese es el número de arcos
Caminos en Grafo
Un camino en un grafo G = (V,E) es una secuencia de arcos (v1,v2),(v2,v3),..,(vn,vn+1) Є E.
El largo del sendero es el número de arcos.El costo del sendero es la suma del costo de los arcos.
Por ejemplo; (1,2),(2,3),(3,5). Largo 23, costo 70.grafo dirigido es un grafo con direcciones sobre los arcos y costos positivos sobre los costos.
Todos los pares de caminos cortos
Dado un rotulado, para un grafo dirigido G = (V,E) encontrar para cada par de vértices
v,w ε V en costo de los caminos (es decir al menos el costo) del camino de v a w.
Se define Ak una matriz de n*n con Ak[i,j] el costo de i a j con vértices internos numerados <k.
Ao[i,j] iguales
* Si i ≠ j y (i,j) Є E, es el costo del arco desde i a j
* Si i ≠ j y (i,j) no pertenece a E, entonces ∞* Si i=j, entonces 0
Calculando Ak
Considerar el camino de i a j con vértices internos 1..k. Así,
•No pasa por k, en su lugar es el costo Ak-1[ i, j].
•Pasa a través de k, en cuyo caso pasa por k solo una vez, por lo que el costoAk-1[i,k] + Ak-1[k,j]
Por lo tanto:
Todas entradas en Ak dependen a fila k y columna k de Ak-1
Las entradas en fila k y columna k de Ak son algunas de las elegidas en Ak-1
Para la fila y columna:
Entonces se pude usar algún arreglo:
Algoritmo Floyd’s
O(n3)
Entonces se pude usar algún arreglo:Algoritmo Floyd’s
Almacenar el más corto camino:
P[i,j] contiene el vértice del camino más corto i a j.
Programación Dinámica