Está en la página 1de 12

Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

Capítulo 9
Introducción a la Complejidad
Computacional

Hasta ahora nos hemos interesado en la algoritmia, que se ocupa del diseño y análisis
sistemático de algoritmos específicos para resolver algún problema dado. Sin embargo,
ningún curso sobre algoritmia estaría completo sin una introducción a la complejidad
computacional. Este campo, paralelo al de la algoritmia, considera globalmente todos los
algoritmos capaces de resolver un problema dado. Esto incluye también a los algoritmos
que aún no han sido inventados.

Usando la algoritmia, podemos probar mediante la proposición y análisis de un algorit-


mo explícito que el problema en estudio se puede resolver en un tiempo del O(f(n)), para
alguna función f(n) que pretendemos reducir tanto como sea posible. Usando complejidad,
por el contrario, tratamos de encontrar una función g(n) tan grande como sea posible para
la cual podamos probar que cualquier algoritmo capaz de resolver correctamente nuestro
problema sobre todas sus instancias debe tomar necesariamente un tiempo en el Ω(g(n)).
A esta función g(n) le llamamos la cota inferior de la complejidad del problema. Podemos
estar completamente satisfechos cuando f(n) ∈ Θ(g(n)), porque entonces sabemos que
hemos encontrado el algoritmo más eficiente posible, excepto quizás por cambios en la
constante multiplicativa oculta. Desafortunadamente, tal situación no se da con demasiada
frecuencia. No obstante, de vez en cuando podemos encontrar incluso el número exacto de
veces que se debe ejecutar alguna operación –como una comparación– para resolver el
problema.

Consideremos como ejemplo introductorio el juego de las veinte preguntas. Una perso-
na elige un entero positivo no mayor que un millón, que la otra persona tiene que adivinar.
Se le permite a la persona realizar 20 preguntas que se puedan contestar con sí o con no. El
que eligió el número debe ser capaz de decidir sin ambigüedad si debe responder afirmati-
va o negativamente a cada pregunta. Lo más adecuado es usar un enfoque DyC para

F.C.A.D – U.N.E.R. 141


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

resolver el enigma, reduciendo con cada pregunta el número de candidatos a la mitad. La


primera pregunta sería “¿el número está entre 1 y 500000?”. Es fácil demostrar que de esta
manera siempre se puede encontrar la solución dentro de las 20 preguntas permitidas,
porque un millón es menor que 220.

Era tarea de la algoritmia encontrar este algoritmo, que muestre que 20 preguntas son
suficientes para resolver el problema. Pero es incumbencia de la complejidad decidir si 20
preguntas son necesarias.

9.1 Objetivos
El estudio de la eficiencia de los algoritmos no puede ser atacado por el argumento
“las computadoras del futuro serán increíblemente rápidas y por lo tanto no interesará
que el algoritmo sea eficiente”. Hay ejemplos que refutan esta afirmación, como el del
número de Fibonacci, o el hecho de que resolver el problema del viajante para 100 ciuda-
des llevaría 100 millones de años. Para resolver estos problemas se necesita una mejora en
los algoritmos; pero no una pequeña mejora, sino una mejora en órdenes de magnitud.

Dado un algoritmo que resuelve un problema, es razonable (y aconsejable) preguntarse


si no existirá un algoritmo más eficiente para el mismo problema.

El objetivo principal de la Complejidad Computacional es por lo tanto clasificar los


problemas de acuerdo a su tratabilidad, tomando el o los algoritmos más eficientes para
resolverlos. Esto es, poder determinar las respuestas a las siguientes preguntas:

¿Cuán tratable es el problema?


Si el problema es tratable, ¿es eficiente el algoritmo?
Si se demuestra que un problema no admite soluciones mejores, entonces se puede
afirmar que el algoritmo es eficiente (salvo por las constantes ocultas). Se dice que un
problema es cerrado si se han encontrado algoritmos que lo resuelven y se ha demostrado
que esos algoritmos son óptimos en cuanto al Θ() del tiempo de ejecución.

La Búsqueda en un arreglo ordenado y el Ordenamiento de un arreglo son problemas


cerrados. El Árbol de cubrimiento minimal de un grafo es un problema abierto, dado que
su cota inferior demostrada es del Θ(a), mientras que el mejor algoritmo conocido no es
lineal (pero mejor que Θ(a log n)).

F.C.A.D – U.N.E.R. 142


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

En general, los distintos grados de tratabilidad son muy subjetivos (varían mucho de
acuerdo al modelo computacional, los recursos disponibles, las variantes de las estructuras
de datos, etc.). Por lo tanto, un objetivo primario del estudio de la complejidad es definir
cuáles problemas son tratables, y cuáles no. Recién después de esto se pueden considerar
distintos grados de tratabilidad o intratabilidad.

Por ejemplo, se puede afirmar que la mayoría de los problemas vistos en este curso son
tratables, o sea que tienen solución para instancias grandes, y una mejora algorítmica o en
el hardware produce una gran ampliación en el conjunto de instancias que se pueden
resolver.

En cambio, hay problemas que no son tratables. Por ejemplo, el problema de las torres
de Hanoi, o el problema del Viajante, que en la práctica sólo se resuelven para instancias
pequeñas. Otro problema intratable es el denominado Monkey Puzzle, una especie
particular de rompecabezas (Figura 9.1). Si se tiene un tablero de n × n, no se conoce algo-
ritmo mejor que probar todas las combinaciones posibles para resolverlo. Esto es Ω(n!).
Para n = 5, generando un millón de configuraciones por segundo, se tardaría 490000
millones de años en resolverlo.

Figura 9.1: Monkey Puzzle

Esta evidencia empírica ha permitido acordar que si un problema admite una solución
polinomial entonces estamos ante un problema tratable; en caso contrario se lo considera
intratable. Para tener una mejor idea de la diferencia entre tratable e intratable:

Problemas tratables:

F.C.A.D – U.N.E.R. 143


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

Función \ n 10 50 100 300 1000


5n 50 250 500 1500 5000
n lg n 33 282 665 2469 9966
n2 100 2500 10000 90000 Un millón
(7 dígitos)
n 3
1000 125000 Un millón 27 millones Mil millones
(7 dígitos) (8 dígitos) (10 dígitos)

Problemas intratables:
Función \ n 10 50 100 300 1000
2n 1024 16 dígitos 31 dígitos 91 dígitos 302 dígitos
n! 3600000 65 dígitos 161 dígitos 623 dígitos inimaginable
(7 dígitos)
nn 11 dígitos 85 dígitos 201 dígitos 744 dígitos inimaginable

Para comparación, el número de protones en el universo es de 79 dígitos, y el número


de microsegundos transcurridos desde el Big Bang es de 24 dígitos.

Esto significa que si suponemos que un algoritmo ejecuta 1000 instrucciones por
microsegundo, el algoritmo tarda:

Problemas tratables:
Función \ n 10 50 100 300 1000
1/10000 1/2500 1/400 1/100 9/100
n2
segundo segundo segundo segundo segundo
n5 0,1 seg 3,2 seg 5,2 seg 2,8 hs 28,1 días

Problemas tratables:
Función \ n 10 50 100 300 1000
1/1000 400 billones
2n 1 segundo 35,7 años ——
segundo de siglos
3,3 billones
nn 2,8 hs —— —— ——
de años

Para comparación, se considera que el Big Bang ocurrió hace aproximadamente 15000
millones de años.

Supongamos que tenemos en la actualidad una computadora en la que ejecutamos


distintos algoritmos para resolver un mismo problema. ¿Cuál es la ventaja de adquirir
una computadora más poderosa?

F.C.A.D – U.N.E.R. 144


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

Instancia máxima que se puede resolver con


Tiempo Algoritmo
Computadora Actual Computadora 100× Computadora 1000×
Θ(n) A 100 × A 1000 × A
Θ(n2) B 10 × B 31,6 × B
Θ(2n) C C + 6,64 C + 9,97

Esto demuestra que los problemas intratables no se resuelven comprando Hardware; el


hecho de que sólo se resuelvan instancias pequeñas es una característica intrínseca del
problema.

9.2 Problemas de Decisión


Dentro de la evolución de la teoría de la complejidad se han encontrado problemas con
características similares, que pueden ser agrupados en categorías para su estudio.

Los problemas de decisión son aquellos donde se busca una respuesta por sí o por no.
Se denominan así porque deciden si una instancia dada es una solución al problema. Los
algoritmos que resuelven problemas de decisión son reconocedores, o comprobadores de
parejas “Instancia, Solución”.

Los problemas de optimización (o de solución) son aquellos en los cuales se busca


minimizar o maximizar (es decir, optimizar) el valor de una solución en un grupo de
soluciones generadas para una entrada específica (instancia). La forma general de exponer
un problema de optimización es

Optimizar c(s) sobre s en F(n)

Un algoritmo que resuelve un problema de este tipo es propiamente un resolvedor o


calculador de soluciones. Para cada Instancia, construye una correspondiente Solución.

Cualquier problema de optimización puede ser manejado como un problema de


decisión incluyendo un valor objetivo K para la instancia n y preguntando si existe o no
una solución factible en el conjunto de soluciones F(n), con el valor de la solución c(s)
optimizado sobre K (para el caso de minimización sería c(s) ≤ K, y c(s) ≥ K para el caso de
maximización).

De esta forma, para propósitos teóricos, es más conveniente tratar con problemas de
decisión que con problemas de optimización. En teoría de complejidad, por lo tanto, se

F.C.A.D – U.N.E.R. 145


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

trabaja con problemas de decisión, ya que como se dijo cualquier problema de optimiza-
ción puede ser reducido a un problema de decisión. Esto se hace para que el estudio de la
complejidad sea uniforme.

Ejemplo: El problema de cobertura de nodos puede ser cambiado de un problema de


optimización a un problema de decisión.

Sea G un grafo definido como G = 〈N, A〉, donde N es el conjunto de nodos y A es el


conjunto de arcos. Una cobertura de nodos de G es un conjunto U de nodos de G, tales que
cualquier arco de G inicia y/o termina en un nodo de U.

El problema de cobertura de nodos reside en encontrar el menor número de nodos. La


Figura 9.2 muestra un ejemplo de grafo y su cobertura de nodos U = {W, S, Y, Z}.

U
V

Z W

Y
X

Figura 9.2: La cobertura de nodos del grafo es {W, S, Y, Z}

Problema de optimización de cobertura de nodos: Encontrar el subconjunto de nodos


menor que sea una cobertura de nodos.
Instancia: Un grafo G.
Respuesta: Una cobertura de nodos de tamaño mínimo.
Problema de decisión de cobertura de nodos: ¿Existe para el grafo G una cobertura S de
tamaño K tal que no exista ninguna de menor tamaño que S?
Instancia: Un grafo G y un valor K.
Respuesta:
• Sí: si hay una cobertura de nodos de tamaño menor o igual a K.
• No: si no existe.

La conversión puede ser hecha encontrando la relación entre K y el tamaño mínimo de


la cobertura.

F.C.A.D – U.N.E.R. 146


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

9.3 Modelos de Computación


El estudio de la complejidad está relacionado con el tipo de cómputo donde se aplica el
algoritmo. Actualmente, los modelos de cómputo se pueden agrupar en dos grandes
conjuntos: determinísticos y no determinísticos.

El modelo determinístico está asociado históricamente a la máquina de Turing, ya que


esta máquina es, asimismo, un modelo matemático estándar que formaliza la noción de
computadora. Una máquina de Turing determinista está formada por:
• Una cinta infinita en ambos sentidos, dividida en celdas numeradas. Cada celda
puede contener un único carácter del conjunto de caracteres que la máquina reconoce.
• Una cabeza de lectura/escritura, que es capaz de leer un carácter de una celda de la
cinta, escribir un carácter en una celda, o cambiar su posición relativa sobre la cinta
una celda en cualquier dirección.
• Una lista finita de estados, tal que en cada momento la máquina está en
exactamente uno de esos estados. Además de los estados comunes q1, … , qs, también
existen tres estados especiales: q0 (el estado inicial), qY (el estado final en un problema
cuya respuesta es “Sí”), y qN (el estado final en un problema cuya respuesta es “No”)
• Un programa, que dirige la máquina a través de las etapas de una tarea particular.

El determinismo estriba en que para una misma entrada, el resultado de aplicar


repetidas veces un algoritmo, siempre es el mismo.

El modelo no determinístico es equivalente a decir que pueden obtenerse resultados


diversos para una misma entrada. Este modelo contiene dos fases: una fase de adivinación
y una de verificación. La fase de adivinación (no determinista) escoge al azar una
estructura que puede ser la solución, y la fase de verificación (determinista) consiste en
determinar si la estructura escogida es una solución. El modelo no determinístico está
asociado a la Máquina de Turing no determinista, la cual adicionalmente a los elementos
de una de tipo determinista, contiene un oráculo o elemento de adivinación.

Un algoritmo no determinista es una herramienta teórica imposible en la realidad. Se


trata de algoritmos similares a los habituales pero que permiten dividir el proceso compu-
tacional en dos procesos paralelos ejecutados simultáneamente por el mismo procesador.

F.C.A.D – U.N.E.R. 147


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

9.4 Problemas P y NP
Al estudiar los problemas de decisión, se pueden encontrar varias clases:

• La clase de problemas P (Polynomial) está formada por todos aquellos problemas


de decisión para los cuales se tiene un algoritmo de solución que se ejecuta en tiempo
polinomial dentro de una máquina determinista.

Se dice que un problema de decisión pertenece a la clase P si existe un algoritmo A y


un número c tales que para cualquier instancia I del problema, el algoritmo A producirá
una solución en tiempo O(Bc), donde B es el número de bits en la cadena de entrada que
representa I.

Para decirlo más brevemente, P es el conjunto de los problemas de decisión fáciles.

La mayoría de los problemas que vimos hasta aquí en el curso pertenecen a la clase P:
¿Se encuentra el número n en este vector? ¿Existe un flujo de valor mayor que K en esta
red? ¿Existe un árbol de cubrimiento en este grafo tal que la suma de los pesos de los
arcos es menor que S? Para cada uno de estos problemas existe un algoritmo rápido (de
tiempo polinomial).

Ejemplo: El problema de encontrar un camino en un grafo dirigido es de clase P.

La entrada del algoritmo es un grafo dirigido G = 〈N, A〉 y dos subconjuntos S y T de


G. La salida del algoritmo es un camino en G de un nodo en S a un nodo en T, si el
camino existe.

• La clase de problemas NP (Non-deterministic Polynomial) está formada por todos


aquellos problemas de decisión para los cuales existe un algoritmo de solución que se
ejecuta en tiempo polinomial dentro de una máquina no determinista. Dicho de otro
modo, no se ha encontrado un algoritmo determinista que lo resuelva en tiempo
polinomial. Pero si se tiene una solución propuesta, estos problemas pueden
determinar en tiempo polinomial si dicha solución es correcta o no.

La clase NP es un poco más sutil. Un problema de decisión Q pertenece a NP si existe


un algoritmo A que hace lo siguiente:

a) Asociado con cada palabra del lenguaje Q (es decir, con cada instancia I para la
cual la respuesta es “Sí”), existe un certificado C(I) tal que, cuando se ingresa el
par (I, C(I)) en el algoritmo, éste reconoce que I pertenece al lenguaje Q.

F.C.A.D – U.N.E.R. 148


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

b) Si I es una palabra que no pertenece al lenguaje Q (es decir, si la respuesta para la


instancia I es “No”), entonces no hay posibilidad de que un certificado C(I) cause
que A reconozca a I como miembro de Q.

c) El algoritmo A opera en tiempo polinomial.

Para decirlo más brevemente, NP es la clase de los problemas de decisión para los
cuales es fácil comprobar la correctitud de una respuesta propuesta, con la ayuda de un
poco de información adicional. Es decir que no se está buscando la forma de encontrar
una solución, sino sólo de verificar que una solución propuesta es realmente correcta.

Ejemplo: El problema de encontrar el máximo cliqué en un grafo es de clase NP.

Un cliqué es un subconjunto de vértices completamente conectado. La entrada del


algoritmo es un grafo G = 〈N, A〉 y un valor entero K. La salida del algoritmo es el
subconjunto de vértices de tamaño K que sea completamente conectado, si el
subconjunto existe. En consecuencia, el problema de decisión asociado es NP.

La relación entre la clase P y la clase NP es estrecha: es muy claro que P ⊆ NP.


Cualquier problema de decisión resuelto por un algoritmo determinístico en tiempo
polinomial también es resuelto por un algoritmo no determinístico en tiempo polinomial,
debido a que cualquier algoritmo determinístico puede ser usado en la fase de verificación
de un algoritmo no determinístico. La relación anterior es fundamental en la teoría de NP–
completitud.

Parece natural suponer que NP es más grande que P. Es decir, uno podría suponer que
hay problemas cuyas soluciones pueden ser rápidamente comprobadas con la ayuda de
cierta información adicional, aún cuando esas soluciones no se puedan encontrar en
tiempo razonable. Sin embargo, no se ha producido (ni probado) ningún ejemplo de tal
problema. Por lo tanto, el problema de determinar si P = NP o P ≠ NP es una de las
preguntas abiertas más importantes hoy en día en esta área. ¿Es posible que para todos los
problemas en NP existan algoritmos deterministas que los resuelvan en tiempo polinomial
y que aún no hayan sido descubiertos? Esto parece improbable ya que mucha gente ha
trabajado sobre estos problemas. Por otro lado, el hecho de que P ≠ NP tampoco ha sido
probado.

F.C.A.D – U.N.E.R. 149


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

9.5 Problemas NP–Completos


La teoría de NP–completitud se basa en el concepto de transformación polinomial.

9.5.1 Transformación polinomial

Una transformación polinomial es una función que permite cambiar la representación


de un problema D1 a otro problema D2 aplicando un algoritmo determinista de tiempo
polinomial. Lo anterior se puede representar como “D1 se transforma a D2”, o “D1 es
rápidamente reducible a D2”. Cualquier elemento del problema D1 tiene un elemento
equivalente en D2. Si se tiene una instancia I1 del problema D1, se la puede convertir, con
sólo una cantidad polinomial de trabajo, en una instancia I2 de D2, de forma tal que I1 e I2
tienen la misma respuesta (“Sí” o “No”).

Estas transformaciones son importantes porque sirven para determinar la pertenencia


de los problemas a las clases P y NP, y permiten definir la clase NP–Completo.

Si D1 se transforma a D2 y D2 pertenece a la clase P, entonces D1 también


pertenece a la clase P, porque, si para cambiar de D1 a D2 se utiliza un algoritmo de
tiempo polinomial y si D2 (ya que pertenece a la clase P) tiene un algoritmo de solución
que se ejecuta en tiempo polinomial, D1 debe tener asociado un algoritmo que lo resuelva
también en tiempo polinomial, y D1 debe pertenecer a la clase P.

Se puede decir, en general, que un problema D1 está en P si cualquier problema que se


sabe está en P, se puede transformar a D1. También se puede decir que un problema D1
está en NP si cualquier problema que se sabe está en NP, se puede transformar a D1.

Un problema de decisión D1 es NP–Completo si pertenece a la clase NP, y


cualquier otro problema D2 que también pertenece a NP, se puede transformar a D1.

Los problemas NP–Completos son los problemas más difíciles en la clase NP, y sus
implicaciones son numerosas. Supongamos que se pudiera probar que un cierto problema
de decisión es NP–Completo. Luego, se podrían dirigir todos los esfuerzos a encontrar un
algoritmo de tiempo polinomial sobre ese único problema. De hecho, si se tuviera éxito en
encontrar ese algoritmo, automáticamente tendríamos un algoritmo rápido para resolver
cualquier problema de NP. La palabra completitud significa que la solución de un
problema de decisión NP contiene, de alguna forma, la solución a todos los problemas de
decisión de la clase NP.

F.C.A.D – U.N.E.R. 150


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

Si D1 se transforma a D2 y D2 es un problema NP–Completo, entonces D1 también


es un problema NP–Completo. Esto es importante, ya que establece que se puede probar
que un problema de decisión D1 es NP–Completo, si algún problema que se sabe es
NP–Completo puede transformarse al primero.

Es decir, un algoritmo rápido para un problema NP–Completo implica algoritmos


rápidos para todos los problemas NP; algoritmos probadamente lentos para un problema
NP implica algoritmos probadamente lentos para todos los problemas NP–Completos.

La siguiente es una lista de propiedades o características interesantes de la familia de


problemas NP–Completos:

• Todos ellos parecen ser computacionalmente muy difíciles, y aún no se han


encontrado algoritmos de tiempo polinomial para ninguno de ellos.

• Tampoco se ha probado que no existan algoritmos de tiempo polinomial para estos


problemas.

• Pero este no es sólo un conjunto aleatorio de problemas difíciles. Si se pudiera


encontrar un algoritmo rápido para un problema NP–Completo, entonces habría
algoritmos rápidos para todos ellos.

• Por el contrario, si se pudiera probar que no existe ningún algoritmo rápido para
uno de los problemas NP–Completos, entonces no podría haber algoritmos rápidos
para ningún otro de estos problemas.

Los problemas NP–Completos tienen toda clase de propiedades maravillosas. Es


extraordinario que cualquier problema de NP pueda ser rápidamente reducido a ese único
problema NP–Completo. Pero hay un detalle a tener en cuenta: ¿existe algún problema
NP–Completo? Porque el punto importante para demostrar que un problema es
NP–Completo es el de tener un problema que sea NP–Completo.

La respuesta es sí, hay problemas NP–Completos. El primero fue el más difícil de


encontrar, pero en 1971, Cook demostró que el problema de satisfacibilidad de una
fórmula proposicional (SAT) es NP–Completo. A partir de ese trabajo, el progreso en este
campo fue mucho más fluido. La prueba utiliza la teoría de las máquinas de Turing.

Teorema 10 (Cook) El problema de Satisfacibilidad de una fórmula proposicional


(SAT) es NP–Completo.

F.C.A.D – U.N.E.R. 151


Algoritmos y Complejidad Unidad 9: Introducción a la Complejidad Computacional

9.5.2 El problema de satisfacibilidad

El problema de satisfacibilidad (SAT) es un problema central en la lógica matemática


y la teoría de la computación. SAT es fundamental para la solución de varios problemas en
razonamiento automático, diseño y manufactura asistida por computadoras, planificación,
visión computacional, bases de datos, robótica, diseño de circuitos integrados, de
arquitectura de computadoras y de redes de computadoras, entre otros.

La satisfacibilidad proposicional es el problema de decidir si existe una asignación de


valores de verdad a los literales de una fórmula proposicional que la hacen verdadera.

Ejemplo: La asignación de valores de verdad que satisfacen la fórmula


(p ∨ ¬q) ∧ (q ∨ r) ∧ (¬r ∨ ¬p)
es p = q = V y r = F , por lo que la fórmula es satisfacible.

Como se ha dicho, el problema de SAT es NP–Completo, y no existe un algoritmo


eficiente (de tiempo polinomial) que lo resuelva.

Una vez probada la pertenencia de SAT al conjunto de los problemas NP–Completos,


mediante transformaciones polinomiales, se ha podido probar la pertenencia de otros
varios problemas a esta misma clase. Como ejemplos se pueden citar el problema de
encontrar un Ciclo Hamiltoniano en un grafo, el problema del Coloreo de un grafo (donde
dos nodos adyacentes no pueden tener el mismo color), el problema del Viajante, y el del
Camino más Largo entre dos nodos de un grafo.

9.6 Problemas NP–Difíciles


Algunas veces se puede demostrar que todos los problemas en NP se pueden
transformar a algún problema A, pero no se puede decir que A sea NP o NP–Completo. Sin
embargo, es indudable que A es tan difícil como cualquier problema en NP, y es entonces
intratable. Para este tipo de problemas se asocia el término de NP–Difíciles, o NP–Duros.

En la literatura también se usa el término NP–Difícil para describir a los problemas de


optimización (que, no siendo problemas de decisión, no son NP) cuya versión de decisión
está en NP–Completo.

F.C.A.D – U.N.E.R. 152

También podría gustarte