BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
Introducción:
Las computadoras actuales de silicio están comenzando a mostrar sus limitaciones: se
están alcanzando los límites impuestos por las leyes de la física en cuanto a la
miniaturización de los componentes necesaria para aumentar la velocidad de proceso y
la capacidad de almacenamiento en las memorias de silicio está siendo sobrepasada con
creces por otras tecnologías (memorias holográficas, ADN). La barrera de los petaflops
(1015 operaciones por segundo) necesaria para complejos problemas de simulación y
optimización y para muchos problemas de la IA no se alcanzará con computadoras
paralelas de silicio clásicas.
La computación biomolecular (con ADN, ARN, proteínas, o con membranas) o la
computación cuántica quizás no sustituyan a los semiconductores de silicio en los PC's
que tenemos sobre nuestras mesas pero probablemente entren en juego como potentes
tecnologías de la futura super-computación paralela avanzada. Estos nuevos modelos no
convencionales no son simples mejoras sobre modelos anteriores de cómputo sino que
aprovechan el paralelismo inherente de los procesos biológicos (ensamblamiento o
hibridación del ADN) y de los procesos físicos (superposición de estados cuánticos).
La frontera entre los problemas `tratables' y los `intratables' o no resolubles de forma
eficiente ha permanecido prácticamente inalterada durante los últimos 40 años. La
computación cuántica parece que ha desplazado esta frontera y demuestra su hegemonía
(al menos teórica) frente a los modelos de cómputo clásicos (máquinas de Turing,
RAM, circuitos) al comprobarse que pueden resolver en tiempo polinómico problemas
que cualquier modelo clásico resolvería en tiempo exponencial; por ejemplo, el
problema de la factorización de números de gran importancia en la criptografía actual.
Creemos que la investigación en la frontera de la biología y la física con las tecnologías
de la información puede llevar al desarrollo de nuevos e importantes sistemas de
información (algoritmos y software) y tecnologías de computación (hardware). La
cuestión es qué y cómo podemos aprender (y entender) de los sistemas biológicos y
físicos y cómo podemos adoptarlos y adaptarlos para desarrollar las tecnologías de la
información del futuro. La computación biomolecular y la computación cuántica
persiguen estos objetivos.
El avance tecnológico actual está permitiendo manipular de forma cada vez más precisa
la materia a nivel molecular e incluso atómico. Estos avances tecnológicos pueden hacer
realidad estos dos nuevos modelos de computación. En el siglo XX se han intentado
simular procesos computacionales presentes en la Naturaleza. En el siglo XXI, los
esfuerzos se encaminarán a utilizar la propia Naturaleza para realiza cómputos. Estos
estudios nos permitirán también descifrar las leyes del procesamiento de la información
en la Naturaleza. Una teoría única de la información que incluya la física, la
computación y la biología.
Problemas P- NP
Para muestra un botón. Clases de complejidad más importantes L | NL | P | NP | Co-NP
| NP-C | Co-NP-C | NP-hard | UP | #P | #P-C | NC | P-C PSPACE | PSPACE-C |
EXPTIME | EXPSPACE | BQP | BPP | RP | ZPP | PCP | IP | PH
___________________________________________________________________
Escuela de Ingeniería en Computación, Universidad de La Serena
1
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
Definición: “La Teoría de la Complejidad Computacional es la parte de la teoría de la
computación que estudia los recursos requeridos durante el cálculo para resolver un
problema”.
Los recursos comúnmente estudiados son el tiempo (número de pasos de ejecución de
un algoritmo para resolver un problema) y el espacio (cantidad de memoria utilizada
para resolver un problema). Se pueden estudiar igualmente otros parámetros, tales como
el número de procesadores necesarios para resolver el problema en paralelo. La teoría
de la complejidad difiere de la teoría de la computabilidad en que esta última se ocupa
de la factibilidad de expresar problemas como algoritmos efectivos sin tener en cuenta
los recursos necesarios para ello.
Los problemas que tienen una solución con orden de complejidad lineal son los
problemas que se resuelven en un tiempo que se relaciona linealmente con su tamaño.
En computación, cuando el tiempo de ejecución de un algoritmo (mediante el cual se
obtiene una solución al problema) es menor que un cierto valor calculado a partir del
número de variables implicadas (generalmente variables de entrada) usando una fórmula
polinómica, se dice que dicho problema se puede resolver en un "tiempo polinómico".
Por ejemplo, si determinar el camino óptimo que debe recorrer un cartero que pasa por n
casas necesita menos de 50n² + n segundos, entonces el problema es resoluble en un
"tiempo polinómico".
De esa manera, tiempos de 2n2 + 5n, ó 4n6 + 7n4 - 2n2 son polinómicos; pero 2n no lo es.
Dentro de los tiempos polinómicos, podemos distinguir los lineales de orden O(n), los
cuadráticos O(n2), cúbicos O(n3), etc... Hoy en día las máquinas resuelven problemas
mediante algoritmos que tienen como máximo una complejidad o coste computacional
polinómico, es decir, la relación entre el tamaño del problema y su tiempo de ejecución
es polinómica. Éstos son problemas agrupados en el conjunto P. Los problemas con
coste factorial o combinatorio están agrupados en el conjunto NP. Estos problemas no
tienen una solución algorítmica, es decir, una máquina no puede resolverlos en un
tiempo razonable. Más adelante se insiste en estas definiciones.
La complejidad en tiempo de un problema es el número de pasos que lleva resolver
dicho problema, a partir del tamaño de la entrada utilizando el algoritmo más eficiente a
disposición. Intuitivamente, si se toma una entrada de longitud n que puede resolverse
en n² pasos, se dice que ese problema tiene una complejidad en tiempo de n². Por
supuesto, el número exacto de pasos depende de la máquina en la que se implementa,
del lenguaje utilizado y de otros factores. Para no tener que hablar del costo exacto de
un cálculo se utiliza la notación O. Cuando un problema tiene costo en tiempo O(n²), en
una configuración de computador y lenguaje dado, este costo será el mismo en la
mayoría de los computadores, de manera que esta notación generaliza la noción de coste
independientemente del equipo utilizado.
Ejemplos
a) Extraer cualquier elemento de un vector. La indexación en un vector lleva el mismo
tiempo sea cual fuere el índice que se quiera buscar. Por tanto, es una operación de
complejidad constante O(1).
b) Buscar en un diccionario tiene complejidad logarítmica. Se puede iniciar la búsqueda
de una palabra por la mitad del diccionario. Inmediatamente se sabe si se ha encontrado
la palabra o, en el caso contrario, en cuál de las dos mitades hay que repetir el proceso
(es un proceso recursivo) hasta llegar al resultado. En cada (sub)búsqueda el problema
(las páginas en las que la palabra puede estar) se ha reducido a la mitad, lo que se
corresponde con la función logarítmica. Este procedimiento de búsqueda (conocido
___________________________________________________________________
Escuela de Ingeniería en Computación, Universidad de La Serena
2
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
como búsqueda binaria o quicksort) en una estructura ordenada tiene complejidad
logarítmica O(ln n).
c) El proceso más común para ordenar un conjunto de elementos tiene complejidad
cuadrática. El procedimiento consiste en crear una colección vacía de elementos. A ella
se añade, en orden, el menor elemento del conjunto original que aún no haya sido
elegido, lo que implica hacer un recorrido completo del conjunto original (O(n), siendo
n el número de elementos del conjunto). Este recorrido sobre el conjunto original se
realiza hasta que queda todos sus elementos están en la secuencia de resultado. Se puede
ver que hay que hacer n selecciones (se ordena todo el conjunto) cada una con un coste
n de ejecución: el procedimiento es de orden cuadrático O(n²). Hay que aclarar que hay
diversos algoritmos de ordenación con mejores resultados que el descrito.
Clases de complejidad
Los problemas se clasifican en conjuntos de complejidad comparable llamados clases de
complejidad.
Definición: “La clase de complejidad P es el conjunto de los problemas de decisión
que pueden ser resueltos en una máquina (de Turing) determinista en tiempo
polinómico, lo que corresponde intuitivamente a problemas que pueden ser resueltos
aún en el peor de sus casos”.
Definición: “La clase de complejidad NP es el conjunto de los problemas de decisión
que pueden ser resueltos en tiempo polinómico por una máquina de Turing nodeterminista”. NP es el acrónimo en inglés de Polinómico No determinista (NonDeterministic Polynomial-time).
La clase NP es importante porque contiene muchos problemas de búsqueda y
optimización para los que se desea saber si existe cierta solución o si existe una mejor
solución que las conocidas. Entre estos están el problema del camino Hamiltoniano o
problema del viajare, donde se quiere saber si existe una ruta óptima que pasa por todos
los nodos en un cierto grafo y el problema de satisfacibilidad booleana (SAT), donde se
desea saber si una cierta fórmula de lógica proposicional puede ser cierta para algún
conjunto de valores booleanos para las variables.
Todos los problemas de esta clase tienen la propiedad de que, sin embargo, cualquier
solución suya puede ser verificada efectivamente.
Dada su importancia, se han hecho muchos esfuerzos para encontrar algoritmos que
resuelvan algún problema de NP en tiempo polinómico. Aún así, para algunos
problemas de NP no es posible encontrar siquiera un algoritmo mejor que simplemente
realizar una búsqueda exhaustiva (éstos son los problemas del conjunto NP-completo).
Definición: “La clase de complejidad NP-completo es el subconjunto de los problemas
de decisión en NP tal que todo problema en NP se puede transformar polinomialmente
en cada uno de los problemas de NP-completo”. Una transformación polinomial es un
algoritmo determinista que transforma instrucciones de un problema en instrucciones
del otro.
Se puede decir que los problemas de NP-completo son los problemas más difíciles de
NP y, muy probablemente, no formen parte de la clase de complejidad P. La razón es
que de tenerse una solución polinómica para un problema de NP-completo, todos los
problemas de NP tendrían también una solución en tiempo polinómico.
Como consecuencia de esta definición, de tenerse un algoritmo en P para uno de los
problemas NP-completos, se tendría una solución en P para todos los problemas de NP.
Esta definición dada fue propuesta por Stephen Cook en 1971. Al principio parecía
sorprendente que existieran problemas NP-completos, pero Cook demostró (teorema de
___________________________________________________________________
Escuela de Ingeniería en Computación, Universidad de La Serena
3
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
Cook) que el problema de satisfacibilidad booleana (SAT) es NP-completo. Desde
entonces se ha demostrado que otros miles de problemas pertenecen a esta clase, casi
siempre por reducción a partir de otros problemas para los que ya se había demostrado
su pertenencia a NP-completo; muchos de estos problemas aparecen en el libro de
Garey and Johnson's de 1979 Computers and Intractability: A Guide to NPcompleteness.
Como ejemplo de un problema NP-completo está el problema de la suma de
subconjuntos que se puede enunciar como sigue: dado un conjunto S de enteros, ¿existe
un subconjunto no vacío de S cuyos elementos sumen cero? Es fácil verificar si una
respuesta es correcta, pero no se conoce mejor solución que explorar todos los 2n-1
subconjuntos posibles hasta encontrar uno que cumpla con la condición.
Actualmente, todos los algoritmos conocidos para problemas NP-completos utilizan
tiempo exponencial con respecto al tamaño de la entrada. Se desconoce si hay mejores
algoritmos, por la cual, para resolver un problema NP-completo de tamaño arbitrario se
utiliza uno de los siguientes enfoques:
Aproximación: Un algoritmo que rápidamente encuentra una solución no
necesariamente óptima, pero dentro de un cierto rango de error. En algunos casos,
encontrar una buena aproximación es suficiente para resolver el problema, pero no
todos los problemas NP-completos tienen buenos algoritmos de aproximación.
Probabilístico: Una algoritmo probabilístico obtiene en promedio una buena solución al
problema planteado, para una distribución de los datos de entrada dada.
Casos particulares: Cuando se reconocen casos particulares del problema para los cuales
existen soluciones rápidas.
Heurísticas: Un algoritmo que trabaja razonablemente bien en muchos casos. En general
son rápidos, pero no existe medida de la calidad de la respuesta.
El saber si las clases P y NP son iguales es el más importante problema abierto en
Computación teórica. Incluso ya se ha mencionado el premio de un millón de dólares
para quien lo resuelva.
Si P = NP, P contendría las zonas NP y NP-completo.
Actualmente los investigadores piensan que las clases cumplen con el diagrama
mostrado por lo que P y NP-completo tendrían intersección vacía. La importancia de la
pregunta P = NP radica en que de encontrarse un algoritmo en P para un problema NP___________________________________________________________________
Escuela de Ingeniería en Computación, Universidad de La Serena
4
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
completo, todos los problemas NP-completos (y por tanto, todos los problemas de NP)
tendrían soluciones en tiempo polinómico. NP-hard
En teoría de la complejidad computacional, la clase de complejidad NP-hard es el
conjunto de los problemas de decisión que contiene los problemas H tales que todo
problema L en NP puede ser transformado polinomialmente en H. Esta clase puede ser
descrita como conteniendo los problemas de decisión que son al menos tan difíciles
como un problema de NP. Esta afirmación se justifica porque si podemos encontrar un
algoritmo A que resuelve uno de los problemas H de NP-hard en tiempo polinómico,
entonces es posible construir un algoritmo que trabaje en tiempo polinómico para
cualquier problema de NP ejecutando primero la reducción de este problema en H y
luego ejecutando el algoritmo A.
Asumiendo que el lenguaje L es NP-completo,
1. L está en NP
2. ∀L' en NP, L' ≤ L
En el conjunto NP-Hard se asume que el lenguaje L satisface la propiedad 2, pero no la
la propiedad 1. La clase NP-completo puede definirse alternativamente como la
intersección entre NP y NP-hard.
Ejemplos
El problema de la suma de subconjuntos es un problema importante en la teoría de la
complejidad y en la criptografía. El problema se define como: dado un conjunto de
enteros, ¿existe algún subconjunto cuya suma sea exactamente cero? Por ejemplo, dado
el conjunto { −7, −3, −2, 5, 8}, la respuesta es SI, porque el subconjunto { −3, −2, 5}
suma cero. Este problema es probablemente el más simple de explicar de los problemas
NP-completos.
Un problema equivalente es: dado un conjunto de enteros y un entero s, ¿existe algún
subconjunto cuya suma sea s? La suma de subconjuntos también puede verse como un
caso especial del problema de la mochila. Existen problemas NP-hard que no son NPcompletos, por ejemplo el problema de parada. Este problema consiste en tomar un
programa y sus datos y decidir si va a terminar o si se ejecutará indefinidamente. Se
trata de un problema de decisión y es fácil demostrar que es NP-hard pero no NPcompleto.
Por ejemplo, el problema de satisfacibilidad booleana puede reducirse al problema de
parada transformándolo en la descripción de una máquina de Turing que prueba todos
los valores de las variables; cuando encuentra una combinación que satisface la fórmula
se detiene y en caso contrario reintenta desde el principio, quedándose en un lazo
infinito. Para ver que el problema de parada no está en NP es suficiente notar que todos
los problemas de NP tienen un algoritmo asociado pero el problema de parada es
indecidible.
Ejemplos:
En el artículo de 2002, "PRIMES in P", Manindra Agrawal con sus estudiantes encontró
un algoritmo que trabaja en tiempo polinómico para el problema de saber si un número
es primo. Anteriormente se sabía que ese problema estaba en NP, si bien no en NPcompleto, ahora se sabe que también está en P.
___________________________________________________________________
Escuela de Ingeniería en Computación, Universidad de La Serena
5
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
Un problema interesante en teoría de los grafos es el de isomorfismo de grafos: Dos
grafos son isomorfos si se puede transformar uno en el otro simplemente renombrando
los vértices. De los dos problemas siguientes:
Isomorfismo de grafos: ¿Es el grafo G1 isomorfo al grafo G2?
Isomorfismo de subgrafos: ¿Es el grafo G1 isomorfo a un subgrafo del grafo G2?
El problema de isomorfismo de subgrafos es NP-completo. Se sospecha que el
problema de isomorfismo de grafos no está ni en P ni en NP-completo, aunque está en
NP. Se trata de un problema difícil, pero no tanto como para estar en NP-completo.
Otros problemas NP-Completos
La forma más sencilla de demostrar que un nuevo problema es NP-completo es primero
demostrar que está en NP y luego transformarlo polinomialmente en un problema que
ya esté en NP-completo. Por ello, resulta útil conocer algunos de los problemas para los
que existe prueba de pertenencia a la clase NP-completo. De algunos de ellos ya se ha
hablado y otros los veremos con más detalle a continuación:








Problema de satisfacibilidad booleana (SAT),
Buscaminas Richard Kaye de la Universidad de Birmingham (England) en
“Minesweeper is NP-complete” publicado en Mathematical Intelligencer volume
22 nº4 páginas 9-15, Año 2000
Tetris
Problema del ciclo hamiltoniano
Problema del vendedor viajero
Problema de isomofirmo de subgrafos
Problema de la suma de subconjuntos
Problema de la clique
Problema de satisfacibilidad booleana
En teoría de la complejidad computacional, el Problema de satisfacibilidad booleana
(SAT) fue el primer problema identificado como perteneciente a la clase de complejidad
NP-completo.
Los circuitos booleanos constan de puertas lógicas llamadas Y, O ó NO. Los datos o
variables que se introducen en estos circuitos son V(verdadero) o F (falso). Cada puerta
acepta un determinado número de datos de entrada y devuelve el valor lógico de esta
combinación. Por ejemplo, una puerta Y(  ) tiene como datos de entrada p, q y
devuelve p  q, cuyo valor es V si tanto p como q eran V o F en cualquier otro caso.
Una puerta NO(  ) transforma una entrada V en una salida F y una entrada F en una
salida V. El problema SAT se pregunta si, para un circuito booleano dado, existe una
selección de datos de entrada que produce una salida V. Si esto puede parecer fácil, no
olvidemos que un circuito puede contener una cantidad enorme de puertas lógicas y, por
tanto, también una cantidad enorme de datos de entrada.
Un ejemplo de SAT sería el saber si existen valores lógicos para p,q,r,s tales que la
expresión  p  r  s    q  rs  es cierta. Se deduce que esto ocurre si (p, q, r, s) =
(Verdadero, Falso, Verdadero, Falso). Sin embargo, para la expresión
p  q   p  q no hay ninguna asignación de verdad de sus variables que la haga
verdadera.
___________________________________________________________________ 6
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
Clique
En Computación, el problema de la Clique o problema de la liga de amigos es un
problema NP-completo según la Teoría de la complejidad computacional.
Una clique en un grafo es un conjunto de vértices dos
a dos adyacentes. En el grafo de la derecha, los
vértices 1, 2 y 5 forman una clique. En cambio, los
vértices 2, 3 y 4 no (dado que 2 y 4 no son
adyacentes).
El problema de la clique es el problema de
optimización que consiste en encontrar una clique de tamaño máximo en un grafo (un
subgrafo completo de tamaño máximo). Este problema se puede enunciar como un
problema de decisión si la pregunta que se hace es saber si existe una clique de tamaño
k en el grafo.
CLIQUE = {<G, k>| G es un grafo con un clique de tamaño mayor o igual a k}
Un ejemplo de algoritmo de fuerza bruta para encontrar una clique en un grafo consiste
en listar todos los subconjuntos de vértices V y verificar para cada uno de ellos si forma
una clique. Este algoritmo es polinómico si k es una constante pero no lo es cuando se
hace depender a k de, por ejemplo, |V|/2.
Un mejor algoritmo consiste en arrancar con cliques de un solo elemento (cualquier
elemento sirve) e intentar mezclar cliques para obtener otras más grandes, hasta que no
queden más mezclas por intentarse. Dos cliques pueden ser mezcladas si cada nodo de
la primera es adyacente a cada nodo de la segunda.
String Matching (búsqueda en texto) como un problema P.
Otro ejemplo de problemas de tipo P, es la solución a través de la Programación
Dinámica para String Matching. El problema “string matching” se formaliza como
sigue. Consideremos que un texto es un array T[1..n] de longitud n y que los pattern o
“formas” es un array P[1..m] de longitud m. Se supone que los elementos de P y T son
caracteres extraídos de un alfabeto finito. El array de caracteres de P y T son a menudos
llamados string de caracteres. Algoritmos String Matching son frecuentemente
utilizados para la búsqueda de formas particulares en las sucesiones de ADN.
Ejemplo: El objetivo es encontrar todas las ocurrencias del pattern P = abaa en el texto
T = abcabaabcabac. Tal como se ve en Fig. 1 el pattern ocurre solamente una vez en el
texto. En este caso todo carácter del pattern esta conectado por una línea vertical y
ensombrecido para caracterizar los efectos del matching.
Una implementación “naive” es la que se propone, pero muy simple de implementar, la
cual se basa en encontrar todos los “shifts” válidos usando un loop que va chequeando
las condiciones P[1 ..m] = T[s+1..s+m] para toda de las n – m + 1 posibles valores de s.
___________________________________________________________________
Escuela de Ingeniería en Computación, Universidad de La Serena
7
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
Naive-String-Matcher(T, P)
n=long[T];
m= long[P]
for s=0 to n-m do
if P[1..m] = T[s+1..s+m] then
print “pattern ocurrió en la posición” s.
Aquí se muestra una propuesta de implementación del algoritmo.
Implementación del algoritmo y ejecución del ejemplo, considerando que el texto T=
abcabaabcabac y el pattern P= abaa, entregando como resultado posición=3
public class KMP_Naive {
static int n = 1;
private static int[] iniSig (String pattern) {
int[] siguiente = new int [pattern.length ()];
int i = 0, j = -1;
siguiente[0] = -1;
while (i < pattern.length () - 1) {
while (j >= 0 && pattern.charAt (i) != pattern.charAt (j))
j = siguiente[j];
i++; j++;
siguiente[i] = j;
}
return siguiente;
}
public static int kmp_Busca(String texto, String pattern) {
int[] siguiente = iniSig (pattern);
int i = 0, j = 0;
n = 1;
while (i < texto.length ()) {
while (j >= 0 && pattern.charAt (j) != texto.charAt (i)) {
j = siguiente[j];
}
i++; j++;
if (j == pattern.length ())
return i - pattern.length ();
}
return -1;
}
public static void main (String[] args) {
String p = "abaa";//pattern P
int[] siguiente = iniSig(p);
for (int i = 0; i < siguiente.length; i++)
System.out.println ("siguiente[" + i + "] = " + siguiente[i]);
System.out.println("posicion = " + kmp_Busca("abcabaabcabac", p));
}
}
La ejecución del mismo considerando como ejemplo el texto T= abcabaabcabac y el
pattern P = abaa, entrega como resultado posición = 3.
___________________________________________________________________
Escuela de Ingeniería en Computación, Universidad de La Serena
8
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
Ahora si el pattern P es relativamente grande y el alfabeto de donde se extraen los
caracteres es razonablemente grande entonces el algoritmo de Boyer-Moore es más
eficiente para String matching.
Longest Common Subsequence”, (LCS).
Dentro de este contexto se encuentran una serie de problemas, entre ellos el hallar la
subsecuencia común más larga entre 2 string, conocido como “Longest Common
Subsequence”, en adelante (LCS).
Este es otro ejemplo clásico de la técnica de programación dinámica. Antes de que
definamos el problema general de la subsecuencia común más largo, empezamos con un
pequeño ejemplo. Suponga que se da un string (como modelo) y un string más largo
(como texto). La idea es saber si los caracteres del modelo aparecen en orden (pero
posiblemente separado) dentro del texto. Si ello ocurre, decimos que el modelo es una
subsecuencia del texto, y si es la subsecuencia más grande por ejemplo "nomi" es una
subsecuencia de "conocimiento" como solución al problema.
Formalmente, digamos que una sucesión X = < x1 , x2 , ....., xm > y otra sucesión Z =<
z1 , z2 , ....., zk > es una subsucesión de X si existe una sucesión de índices estrictamente
creciente i1 , i2 , ....., ik de índices de k, tal que para todo j=1, 2, 3..., k, se tiene x i j = z j.
Por ejemplo, Z=<B, C, D, B> es una subsucesión de X= <A, B, C, B, D, A, B>, con
subíndices <2, 3, 5, 7>. Dadas dos secuencias X e Y, se dice que una sucesión Z es una
subsucesión común de X e Y si Z es una subsucesión de ambas , es decir de X e Y. Por
ejemplo, si X= <A, B, C, B, D, A, B> , Y= < B, D, C, A, B, A> entonces la sucesión
<B, C, A> es una subsucesión común de X e Y. Observar que <B, C, A> no es la más
larga de X e Y, pues <B, C, B, A> es también común a ambas y tiene longitud 4. Notar
que tampoco es única, pues la sucesión <B, D, A, B> también lo es. Sin embargo, no
existe LCS de longitud 5 o mayor.
¿Por qué podríamos querer nosotros resolver el problema de la subsecuencia común
más larga?
Hay varias aplicaciones que motivan este estudio.
* En la biología molecular. Sucesiones de ADN (genes) pueden representarse como
sucesiones de cuatro elementos básicos ACGT que se corresponden a las cuatro
submoleculas que forman el ADN. Cuando los biólogos encuentran una nueva sucesión,
ellos quieren saber qué otras sucesiones son similares a ella. De allí que la computación
de las dos sucesiones similares pasan por encontrar la longitud de su subsecuencia
común más largo.
* Comparación de archivos. En Unix-Linux comandos "diff" se usan para comparar
dos versiones diferentes del mismo archivo, para determinar qué cambios se han hecho
al archivo. Funciona encontrando una subsecuencia común más larga de las líneas de los
___________________________________________________________________
Escuela de Ingeniería en Computación, Universidad de La Serena
9
Problemas P – NP
BioInformática
Dr. Eric Jeltsch F.
dos archivos; en donde cualquier línea en la subsecuencia no se ha cambiado. En este
caso debemos pensar que cada línea de un archivo es un carácter dentro de un string.
Un approach “fuerza bruta” para resolver LCS es enumerar todas las subsecuencias de
X y chequearlas todas ellas para ver si es también subsecuencia de Y, hasta encontrar la
subsecuencia más larga. Estas observaciones nos dan un algoritmo recursivo altamente
ineficiente, pues recordar que toda subsecuencia de X corresponde a un subconjunto de
los índices {1, 2, 3,..., m} de X, existiendo 2m subsucesiones de X, de manera que el
tiempo es exponencial, haciéndolo impracticable para sucesiones más largas.
Basado en Teorema 16.1 pág. 315 (CLR) podemos admitir una subestructura optimal de
un LCS, y en este contexto al igual que en el problema de Parentización de Matrices se
establece una recurrencia para el costo de una solución optimal. Se define c[i,j] como la
longitud de un LCS de secuencias Xi , Yj. Si i=0 o j=0 una de las sucesiones tiene
longitud 0, así LCS tiene longitud 0. La subestructura optimal de LCS está dada por la
formula recursiva:
0
i0 o j0


c[i, j ]  
c[i  1, j  1]  1
i, j  0 y xi  yi
m ax(c[i, j  1], c[i  1, j ]) i, j  0 y x  y
i
i

Basada en estas ecuaciones podríamos escribir un procedimiento recursivo para
computar la longitud de un LCS de 2 secuencia, pues existen solamente O(mn
problemas distintos.
int lcs_long(char * A, char * B)
{
if (*A = = ' \0 ' || *B = = ' \0 ') return 0;
else if (*A == *B) return 1 + lcs_long(A+1, B+1);
else return max(lcs_long(A+1,B), lcs_long(A,B+1));
}
Sin embargo, el objetivo es usar Programación Dinámica. El procedimiento considera 2
sucesiones X = < x1 , x2 , ....., xm > e Y =< y1 , y2 , ....., yn > como entrada, se procede a
almacenar los valores c[i,j], en una tabla c[0..m, 0..n] cuyas entradas son computadas
primera fila de c es llenada de izq. a der., luego la segunda fila, y así sucesivamente. Al
mismo tiempo se mantiene una tabla
b[1..m, 1..n] para simplificar la construcción de una solución optimal.
LCS-Long(X, Y)
m= long[X]
n= long[Y]
for i=1 to m
do c[i,0]=0
for j=1 to n
do c[0, j]=0
for i=1 to m
do for j=1 to n
do if xi = yj
then c[i, j]= c[i -1,j -1] + 1
b[i, j] =”
“
___________________________________________________________________ 10
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
if else c[i -1, j ]  c[i , j -1 ]
then c[i, j]= c[i -1,j ]
b[i, j] =”
“
else c[i, j]= c[i,j - 1]
b[i, j] = ”
“
return c y b.
La figura siguiente muestra la tabla que se genera por el procedimiento anterior sobre la
secuencia X= <A, B, C, B, D, A, B> e Y= < B, D, C, A, B, A>. El tiempo de ejecución
del procedimiento es claramente O(mn).
El siguiente procedimiento recursivo imprime la salida de LCS de X e Y. La llamada
inicial es printLCS(b, X, long[X], long[Y]).
printLCS(b, X, i, j).
if i=0 o j=0
then return
if b[i, j] = “
”
then printLCS(b, X, i -1, j -1) print xi
else if b[i, j] = “
”
then printLCS(b, X, i -1, j )
else printLCS(b, X, i , j – 1 )
Para la tabla b en figura anterior este procedimiento imprime”BCBA”.
Implementación
/*
Hallar la Longest Common Subsequence, LCS de 2 secuencias como
entrada, usando Programación
Dinámica.
Considerar que el programa
lee los argumentos de la línea de comando. El primer argumento es la
cadena X de caracteres o string, en este caso se consideran solo
enteros(int) mientras que el segundo argumento es la cadena Y de
caracteres o string, también enteros(int). La línea de comando es: x1
x2 ... xm . y1 y2 ... yn. Para notar el termino de una cadena con
___________________________________________________________________ 11
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
respecto al inicio de la
separador. Ejemplo de uso
Problemas P – NP
otra
se
considera
Dr. Eric Jeltsch F.
un
punto
"."
como
>java LCS 1 0 0 1 0 1 0 1 . 0 1 0 1 1 0 1 1 0
1 0 0 1 0 1 0 1
0 1 0 1 1 0 1 1 0
LCS tiene longitud: 6
1 0 0 1 1 0
*/
public class LCS {
public static void main(String[] args) {
int[] x, y; // las 2 secuencia
int n, m;
// x's van de x1 a xn; y's van de y1 a ym
int[][] longit; // longit[i][j] es la longitud de la
subsucesion
//comun mas grande de la long-i subsucesion de los x's, y la long-j
//subsucesion de los y's.
int[][] reconstruir;//es la variable "b" ,
//util para simplificar la construccion de una solucion optimal.
int i, j, k, xs, ys;
// lee la linea de comando con los argumentos
k = args.length;
i=0;
while (! args[i].equals("."))
i++;
n = i;
m = k - i-1;
x = new int[n+1]; // parten los indices en 1
y = new int[m+1];
for (j=0; j<i; j++)
x[j+1] = Integer.parseInt(args[j]);
for (j=0; j<k-i-1; j++)
y[j+1] = Integer.parseInt(args[i+1+j]);
longit = new int[n+1][m+1];
reconstruir = new int[n+1][m+1];
System.out.println();
for (j=1; j <= n; j++)
System.out.print(x[j]+" ");
System.out.println();
for (j=1; j<= m; j++)
System.out.print(y[j]+" ");
System.out.println();
//Si uno del par de sucesiones tiene longitud 0, entonces el
//largo de su LCS es también 0.
for (xs = 1; xs <= n; xs++)
longit[xs][0] = 0;
for (ys = 1; ys <= m; ys++)
longit[0][ys] = 0;
// Ahora calculamos LCS que sucesivamente compara prefijos de x
___________________________________________________________________ 12
Escuela de Ingeniería en Computación, Universidad de La Serena
Problemas P – NP
BioInformática
Dr. Eric Jeltsch F.
// con prefijos de y
for (xs = 1; xs <= n; xs++) {
for (ys = 1; ys <= m; ys++) {
if (x[xs] == y[ys]) {
longit[xs][ys] = longit[xs - 1][ys - 1] + 1;
reconstruir[xs][ys] = 3;
// "3" es la flecha diagonal.
//Indica los elementos que han sido seleccionados
// (vea CLR pag. 317)
}
else if (longit[xs - 1][ys] >= longit[xs][ys-1]) {
longit[xs][ys] = longit[xs-1][ys];
reconstruir[xs][ys] = 1;
// "1" es la flecha horizontal
}
else {
longit[xs][ys] = longit[xs][ys-1];
reconstruir[xs][ys] = 2;
// "2" es la flecha vertical
}
}
}
System.out.println("LCS tiene longitud: " + longit[n][m]);
printLCS(reconstruir, x, n, m);
System.out.println();
}
private static void printLCS(int[][]reconstruir, int[] x,int n, int m)
{
if (n==0 || m==0) {
System.out.println();
return;
}
else if (reconstruir[n][m] == 3) {
printLCS(reconstruir, x, n-1, m-1);
System.out.print(" " + x[n]);
}
else if (reconstruir[n][m] == 2)
printLCS(reconstruir, x, n, m-1);
else
printLCS(reconstruir, x, n-1, m);
}
}
___________________________________________________________________ 13
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
Longest increasing subsequence. (LIS).
Bajo un esquema similar es posible presentar la siguiente aplicación: Dada una sucesión
de enteros X = < x1 , x2 , ....., xm >, los cuales no contienen elementos duplicados,
entonces es posible diseñar un algoritmo para encontrar la subsucesión creciente más
grande xi1  xi2  ....  xik, donde i1  i2  ....  ik que puede encontrarse en X.
También conocido como Longest increasing subsequence. (LIS). Por ejemplo, la
subsucesión más grande de {3, 1, 4, 5, 9, 2, 6, 0, 7, 8, 12, 10} es {3, 4, 5, 6, 7, 8, 12} y
otra es {1, 4, 5, 6, 7, 8, 10}.
Implementación:
/*
Observación:
Esta es una solucion para encontrar una ( de varias posibles)
subsucesión creciente más larga que esta insertada en una sucesión de
simbolos. Ejemplo de uso:
> java LIS 3 5 6 8 9 12 23 4
3 5 6 8 9 12 23 4
^ ^ ^ ^ ^ ^ ^
Una LIS tiene longitud 7.
*/
public class LIS {
public static void main(String[] args) {
int n; // la longitud de la suc de entrada
int[] x; // la sucesion de entrada
int[] lis; // lis[i] es la longitud de la LIS(longest increasing
//subsequence), cuyo miembro final es x[i].
int[] previo; /* si x[i] pertenece a una LIS determinada por el
algoritmo, previo[i] es el indice de los predecesor x[i]'s en
la LIS. El miembro inicial de la LIS tiene previo[i] = n. */
boolean[] en_LIS; // en_LIS[i] es true ssi x[i] esta en la LIS.
int i, j, k, lis_valor, lis_max, k_max, i_max, fin_de_longest;
// inicializar variables y leer la sucesión de entrada, desde la línea
//de comando.
n = args.length;
x = new int[n];
lis = new int[n];
previo = new int[n];
en_LIS = new boolean[n];
for (i=0; i < n; i++)
x[i] = Integer.parseInt(args[i]);
// hallar una LIS, sin contar la existencia del total de ellas.
lis[0] = 1;
previo[0] = n;
i_max = 0;
fin_de_longest = 0;
for (i=1; i<n; i++) {
lis_max = 0;
k_max = 0;
for (k=0; k < i; k++) {
___________________________________________________________________ 14
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
lis_valor = (x[k] < x[i] ? 1 : 0) * lis[k];
if (lis_valor > lis_max) {
lis_max = lis_valor;
k_max = k;
}
}
lis[i] = lis_max + 1;
if (lis_max == 0)
previo[i] = n;
else
previo[i] = k_max;
if (lis[i] > i_max) {
i_max = lis[i];
fin_de_longest = i;
}
}
//marca todos los elementos que estan en la LIS
j = fin_de_longest;
en_LIS[j] = true;
while (previo[j] != n) {
j = previo[j];
en_LIS[j] = true;
}
//print la sucesión de entrada
System.out.println();
for (i=0; i<n; i++)
System.out.print(x[i] + " ");
System.out.println();
//marca los elementos que estan en la LIS
for (i=0; i<n; i++) {
if (en_LIS[i])
System.out.print("^" + rellenar(x[i]) + " ");
else
System.out.print(" " + rellenar(x[i]) + " ");
}
System.out.println();
System.out.println("Una LIS tiene longitud" + lis[fin_de_longest]);
}
//return el número de digitos en n
private static int digitos(int n) {
int m = n / 10;
if (m == 0)
return 1;
else
return( 1 + digitos(m));
}
/*return un string de whitespace, de longitud una menor que el
número de dígitos en el argumenmto de entrada.*/
private static String rellenar(int n) {
int d = digitos(n) - 1;
StringBuffer rellenar = new StringBuffer();
for (int i = 0; i < d; i++)
rellenar.append(" ");
___________________________________________________________________ 15
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
return (rellenar.toString());
}
}
Camino Hamiltoniano
Sea G un grafo dirigido completo con N vértices y con un costo c(i,j) para cada arco
(i,j). Se trata de hallar un camino dirigido que partiendo de cualquier vértice pase por
cada uno de los otros una sola vez y que su costo sea mínimo. Un tal camino se llama
hamiltoniano.
Consideremos un ejemplo de aplicación. Se tienen N lotes para elaborar por una
máquina, uno por vez. Cuando se termina de procesar el lote i, y antes de comenzar el
lote j, se pierde un tiempo c(i,j) para ajustar la máquina. Se pregunta cual debe ser el
orden en que deben ser elaborados los lotes para que sea mínimo el tiempo total perdido
para los ajustes. Acá los lotes están representados por los vértices del grafo, (i,j)
significa que el lote j se procesa a continuación del lote i y c(i,j) es el tiempo perdido
por el ajuste. Entonces el operador J comienza decidiendo el orden de entrada de los
lotes en la máquina. Llega el operador P, al cual J le informa todos lotes que faltan
ordenar y, del resto de lotes, solo le dice cual fue el último ordenado. Llamemos i al
último lote ordenado y sea S el conjunto de lotes que falta ordenar. Denotemos (i,S) al
estado del problema, es decir, P tiene toda la información que necesita para seguir
decidiendo el orden de los lotes S. Llamemos j el siguiente lote que decide P. Entonces
el siguiente estado será (j,S-{j}). Así los arcos del grafo para este problema son de la
forma (i,S)(j,S) donde jS. Los estados (i,S) de este grafo quedan particionados por
card(S) y se trata de encontrar un camino optimo que parta de un (i,S) con card(S)=N-1
y llegue a un (i,S) con card(S)=1
Empezamos los cálculos del camino mínimo partiendo de conjuntos S con un solo
elemento.
f(i,{k})= c(i,k) i,k=1,2,...,N ik, para k=2,3,...,N-1
f(i,S)= min jS {h(i,j)+f(j,S-{j})}, donde card(S)=k e iS. El j que realiza el mínimo se
llama j(i,S). El procedimiento de calculo tiene N-2 iteraciones. En la iteración k
(2kN-1) calculamos f(i,S) y j(i,S) para todo (i,S) tal que card S=k e iS. Para saber
cual es el primer lote a fabricar encontramos un i1 tal que f(i1,S1) sea mínimo con
card(S)=N-1 y luego usamos j(i,S) reiteradamente. Es decir, si j1, j2, ...,jN la solución
optima, la misma esta dada por
j1 = i1
___________________________________________________________________ 16
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
j2= j( j1, S1 -{j1})
j3= j( j2 , S1 -{j1,j2})
...
jN= j( jN-1, S1-{j1,j2,...,jN-1})
Conteo de operaciones
El problema que acabamos de exponer es típico de una clase de problemas (NP-Hard)
para los cuales los algoritmos que se conocen son ineficientes en el sentido que el
tiempo de cálculo crece exponencialmente con el tamaño del problema. Mostramos que
este es el caso para este algoritmo.
Consideremos el numero de operaciones de suma o comparación en la iteración k. En la
iteración k, f(i,S) debe calcularse para (N-k) 

N
 distintos argumentos (i,S) y para cada
k
argumento deben hacerse 2k sumas y comparaciones. Por lo tanto el número total de
N 1
N 1
N
operaciones es :  2 k ( N  k )   N ( N  1) 2
k
k 1
Por otra parte en la iteración k+1 debe tenerse en la memoria activa todos los valores de

N
f(i,S) con card(S)=k, un total de (N-k)
k
números. Esta expresión tiene su máximo
para =N/2. Usando la formula de Stirling obtenemos Memoria: N / 2 2
N
Una operación elemental por la computadora requiere 4/(33106) segundos y un número
entero ocupa 2 bytes. Usando estos datos, el problema para N=25 requiere 20 min para
ser resuelto y 3300 Mb de memoria.
Shortest Common Superstring Problem (SCS), como problema NP-Hard
Sea S = {s1,…,sn} un conjunto de strings (blocks) sobre algún alfabeto Σ. Un superstring
de S es un string x tal que todo si en S es un substring de x. El problema es hallar el
shortest (common) superstring. Este problema se ha demostrado que es NP-Completo.
Esto significa que no podríamos esperar que se encuentre una solución optimal en
tiempo polinomial. No obstante se ha realizado una conjetura que usa la estrategia
greedy.
Ejemplo:
Sea S = {ate, half, lethal, alpha, alfalfa}. Un trivial superstring es
“atehalflethalalphaalfalfa” de longitud 25 (que es una simple concatenación de todos los
bloques). Una shortest common superstring es “lethalphalfalfate” de longitud 17. Notar
que una permutación comprimida de los bloques es actualmente un superstring.
___________________________________________________________________ 17
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
Computación por ADN
Algunos de los problemas a los que nos enfrentamos en computación no pueden ser
resueltos de una manera lineal, es decir, los recursos que se necesitan para encontrar una
solución (tiempo, espacio, ...) crecen exponencialmente respecto a su complejidad. Por
ejemplo, hallar una clave. La única manera de hacerlo sería ir probando todas las
combinaciones posibles. Siendo una clave de m posibles caracteres diferentes y siendo n
su longitud, el tiempo que tardaría un computador en encontrar la solución sería mn.
Hasta ahora lo que estamos acostumbrados a tratar son modelos de computación
convencionales, basados en el modelo de Turing, que es un modelo orientado a
máquinas. Sin embargo, recientes estudios y experimentos han permitido vislumbrar
una tecnología más allá del silicio, que rebasa sus capacidades. El problema anterior de
hallar una clave podría ser resuelto en un tiempo constante.
Más adelante se observó cierta similitud entre algunos procesos matemáticos con
algunos procesos biológicos, dando lugar a la idea de que podrían construirse máquinas
basadas en la biología. En noviembre de 2001, Shapiro realizó una simulación de una
máquina de Turing con moléculas de ADN.
Las moléculas de ADN son cadenas dobles de azúcar en cuyos extremos se encuentra
una base nitrogenada. Dicha base nitrogenada puede ser del tipo A, C, G o T. Dichas
bases se combinan entre sí mediante un enlace de hidrógeno por parejas enfrentadas:
A<-> T y G<-> C. De esta manera, las cadenas se van uniendo formando una larga
hélice.
Utilizando las moléculas de ADN, Leonard Adleman consiguió resolver el problema del
camino hamiltoniano con siete nodos. En este problema se recibe un grafo direccionado,
de manera que hay que encontrar un camino que lleve desde un nodo inicial a un nodo
final pasando una y sólo una vez por cada una de sus aristas. La manera tradicional de
resolverlo es mediante un algoritmo exponencial, probando todos los caminos y luego
comparándolos. Adleman consiguió realizar un algoritmo lineal.
Especificó trece operaciones posibles a realizar con las moléculas de ADN:
desnaturalización, renaturalización, medida de la longitud, extracción, alargar, copiar,
síntesis, acortar, cortar, empastar, alterar, PCR y lectura.
De estas operaciones utilizó únicamente:

Síntesis
Creación de una molécula de ADN con una base concreta.

Desnaturalización
Formar dos hebras simples a partir de una helicoidal calentando lentamente la
solución de ADN.

Renaturalización
Obtener una doble cadena de ADN a partir de dos simples. Esto se hace con un
enfriado lento que recupera los enlaces de hidrógeno. Las ases tienen que ser
complementarias para que encajen.
___________________________________________________________________ 18
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática

Problemas P – NP
Dr. Eric Jeltsch F.
Medida de la longitud
Cuenta el número de pares de bases. Como la molécula de ADN está cargada
negativamente, se puede contar según su carga. También puede hacerse según su
masa.

Extracción o selección
Dados un tubo (para poner los datos) y una cadena, clasifica las moléculas del
tubo según si contienen o no a una cadena, elegida previamente, como
subcadena.Puede que haya moléculas repetidas.
El experimento consistía en codificar cada nodo X mediante dos cadenas de ADN: X y
X'. De esta manera identificaba cada arco mediante la unión de dos cadenas: si un arco
va de A (identificado por A y A') a B (identificado por B y B'), el arco estará
representado por la unión de A' y B. Si el arco va de B a A, la codificación será B'A.
Adleman metió en un mismo recipiente todas las representaciones de arcos junto con las
cadenas complementarias codificando los nodos completos (X seguido de X'), cada una
de ellas repetida muchas veces. Una vez hecho esto, comenzó a renaturalizar.
De esta forma, se unen las cadenas que encajan. Para que dos cadenas encajen tiene que
existir una cadena complementaria que las una. Es decir, las cadenas con la codificación
de los nodos obligan a unir a las cadenas que tienen un arco que empieza en ese mismo
nodo y con otro arco que termina en él. Así, cada hélice que se va formando codifica un
camino a lo largo del grafo. Una vez que las moléculas están suficientemente acopladas,
se pasa a la fase de deshechar los caminos que no sean hamiltonianos.
Como sabía que tenía que pasar una sola vez por cada nodo, fue separando las cadenas
que no tenían longitud siete. Una vez obtuvo todas las cadenas de longitud siete,
comprobó las que tenían como primer nodo el nodo inicial y como último nodo, el nodo
final. De las que quedaron seleccionó las que tenían todos los nodos (es decir, fue
comprobando nodo por nodo que estaba incluido en la cadena). Las cadenas resultantes
eran caminos hamiltonianos.
Visto así podría parecer un proceso largo y tedioso que sería fácilmente resuelto
mediante ordenador. Pero si se automatizara el proceso, veríamos que el número de
pasos, además de ser pequeño, es constante, sea cual sea el tamaño del problema. Sin
embargo, resuelto mediante ordenadores convencionales, este problema puede costar
tanto como para volverse irresoluble.
___________________________________________________________________ 19
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
28/nov/01
¿Computadoras de ADN?
Según la agencia Reuter, científicos israelitas construyeron una computadora con ADN
tan diminuta que un millón de ellas podría caber en un tubo de ensayo y realizar 1.000
millones de operaciones por segundo con un 99,8 por ciento de precisión.
La periodista Patricia Reaney, comenta en el cable de esta agencia fechado el 22 de
noviembre que, en lugar de usar cifras y fórmulas para resolver un problema, las
operaciones de entrada y salida de datos, y los programas de la microscópica
computadora están formados por moléculas de ADN que almacenan y procesan la
información codificada en organismos vivos.
Los científicos consideran esas computadoras de ADN como futuras competidoras de
sus parientes más convencionales ya que la miniaturización está llegando a sus límites,
y el ADN tiene el potencial de ser mucho más rápido que las computadoras
convencionales.
"Hemos construido una computadora, a nanoescala y formada por biomoléculas, que es
tan pequeña que no se puede hacer funcionar una a una. Cuando un millón de millones
de computadoras funcionan a la vez son capaces de realizar 1.000 millones de
operaciones", dijo a Reuters el profesor Ehud Shapiro, del Instituto Weizman, en Israel.
Es la primera máquina de computación programable de forma autónoma en la cual la
entrada de datos, el software y las piezas están formados por biomoléculas.
Aunque es demasiado sencilla como para tener aplicaciones inmediatas, podría formar
la base de una computadora de ADN en el futuro, la cual operaría dentro de las células
humanas, actuaría como un dispositivo de vigilancia para detectar posibles cambios que
puedan causar enfermedades, y sintetizaría medicamentos para curar dichos
padecimientos.
El modelo podría asimismo formar la base de computadoras que luego se podrían usar
para búsquedas en las bibliotecas de ADN sin necesidad de secuenciar cada molécula, lo
que podría acelerar el conocimiento sobre el ADN.
"La célula viva contiene increíbles máquinas moleculares que manipulan las moléculas
codificadoras de información, como el ADN y el ARN, su pariente, en formas que son
esencialmente muy similares a la computación", dijo Shapiro, director del equipo de
investigación que desarrolló la computadora de ADN.
"Al no saber aún cómo modificar de manera eficaz esas máquinas, o crear unas nuevas.
El truco es hallar máquinas que ya existen en la naturaleza y que, cuando se combinen,
puedan ser dirigidas hacia la computación", añadió.
En un artículo publicado en la revista científica Nature, Shapiro y su equipo describen
su computadora de ADN, la cual es un modelo molecular de una de los equipos de
computación más simples, el automatón, que puede responder a ciertas preguntas que
requieren sólo un sí o un no.
Los datos se representan por pares de moléculas en una cadena de ADN y dos enzimas
naturales que actúan como un equipo para leer, copiar y manipular el código. Cuando se
___________________________________________________________________ 20
Escuela de Ingeniería en Computación, Universidad de La Serena
BioInformática
Problemas P – NP
Dr. Eric Jeltsch F.
mezcla todo en un tubo de ensayo, el software y el equipo operan la molécula de entrada
de datos para crear los datos de salida.
Lo más interesante es que la computadora de ADN consume muy poca energía, por lo
que si se coloca dentro de la célula no necesitaría mucha energía para funcionar.
Bibliografía
- Cormen, y otros. McGraw-Hill
- Baase, Sara. “Computer algorithms: introduction to design and analysis”. Capítulo 7.
Addison-wesley. Reading. 1983.
En la Web:
http://web. mat.bham.ac.uk/R.W.Kaye/minesw/minesw.htm
http://www.cecm.sfu.ca/personal/jborwein/algorithms.html
http://es.wikipedia.org/wiki/Tiempo_polin%C3%B3mico
http://es.wikipedia.org/wiki/NP
http://es.wikipedia.org/wiki/Tetris
http://es.wikipedia.org/wiki/NP-completo
http://es.wikipedia.org/wiki/Buscaminas
http://es.wikipedia.org/wiki/Problema_de_satisfacibilidad_booleana
http://es.wikipedia.org/wiki/Problema_de_la_clique
http://www.claymath.org/Popular_Lectures/Minesweeper/
http://www.claymath.org/millennium/P_vs_NP/
http://www.computer.org/cise/articles/Top_Algorithms.htm
http://axxon.com.ar/not/c-108CompuADN.htm
___________________________________________________________________ 21
Escuela de Ingeniería en Computación, Universidad de La Serena
Descargar

Problemas NP - Universidad de La Serena