Analisis de Algoritmo y Complejidad Computacional

Post on 05-Jul-2015

575 views 1 download

Transcript of Analisis de Algoritmo y Complejidad Computacional

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