<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6032501312965262597</id><updated>2012-02-12T06:31:52.020-08:00</updated><category term='Problemas de programación dinámica'/><category term='Definición de programación dinámica'/><category term='Conceptos de programación dinámica'/><category term='Libros sobre Programación Dinámica'/><category term='Funciones Java con programación dinámica'/><title type='text'>Programación dinámica.</title><subtitle type='html'>Aprende programación dinámica de forma fácil.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-745562490673270055</id><published>2009-06-01T07:44:00.000-07:00</published><updated>2009-06-01T07:55:34.808-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Problemas de programación dinámica'/><title type='text'>EL ALGORITMO DE DIJKSTRA</title><content type='html'>Sea un grafo ponderado g = (V,A), donde V es su conjunto de vértices, A el conjunto de arcos y sea L[i,j] su matriz de adyacencia. Queremos calcular el camino más corto entre un vértice vi tomado como origen y cada vértice restante vj del grafo.&lt;br /&gt;El clásico &lt;span style="font-weight: bold;"&gt;algoritmo de Dijkstra&lt;/span&gt; trabaja en etapas, en donde en cada una de ellas va añadiendo un vértice al conjunto D que representa aquellos vértices para los que se conoce su distancia al vértice origen. Inicialmente el conjunto D contiene sólo al vértice origen.&lt;br /&gt;Es posible plantear el &lt;span style="font-weight: bold;"&gt;algoritmo de Dijkstra&lt;/span&gt; en términos de la &lt;span style="font-weight: bold;"&gt;Programación Dinámica&lt;/span&gt;, y de esta forma aprovechar el método de diseño y las ventajas que esta técnica ofrece.&lt;br /&gt;En primer lugar, observemos que es posible aplicar el principio de óptimo en este caso: si en el camino mínimo de vi a vj está un vértice vk como intermedio, los caminos parciales de vi a vk y de vk a vj han de ser a su vez mínimos.&lt;br /&gt;Llamaremos D(j) al vector que contiene el camino mínimo desde el vértice origen i = 1 a cada vértice vj, 2 &lt;=j &lt;=n, siendo n el número de vértices. Inicialmente D contiene los arcos L(1,j), o bien ∞ si no existe el arco. A continuación, y para cada vértice vk del grafo con k &lt;&gt;1, se repetirá:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/__9gdQlyIwfg/SiPpeb76cOI/AAAAAAAAACs/E6gmcRAWFSg/s1600-h/Dibujo.bmp"&gt;&lt;img style="cursor: pointer; width: 252px; height: 30px;" src="http://1.bp.blogspot.com/__9gdQlyIwfg/SiPpeb76cOI/AAAAAAAAACs/E6gmcRAWFSg/s320/Dibujo.bmp" alt="" id="BLOGGER_PHOTO_ID_5342370292095938786" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;De esta forma el &lt;span style="font-weight: bold;"&gt;algoritmo&lt;/span&gt; que resuelve el problema puede ser implementado&lt;br /&gt;como sigue:&lt;br /&gt;&lt;br /&gt;CONST n = ...; (* numero de vertices del grafo *)&lt;br /&gt;TYPE MATRIZ = ARRAY [1..n],[1..n] OF CARDINAL;&lt;br /&gt;  MARCA = ARRAY [1..n] OF BOOLEAN;(* elementos ya considerados*)&lt;br /&gt;  SOLUCION = ARRAY [2..n] OF CARDINAL;&lt;br /&gt;&lt;br /&gt;PROCEDURE Dijkstra(VAR L:MATRIZ;VAR D:SOLUCION);&lt;br /&gt;VAR i,j,menor,pos,s:CARDINAL; S:MARCA;&lt;br /&gt;BEGIN&lt;br /&gt;FOR i:=2 TO n DO&lt;br /&gt;S[i]:=FALSE;&lt;br /&gt;D[i]:=L[1,i]&lt;br /&gt;END;&lt;br /&gt;S[1]:=TRUE;&lt;br /&gt;FOR i:=2 TO n-1 DO&lt;br /&gt;menor:=Menor(D,S,pos);&lt;br /&gt;S[pos]:=TRUE;&lt;br /&gt;FOR j:=2 TO n DO&lt;br /&gt;IF NOT(S[j]) THEN&lt;br /&gt;D[j]:= Min2(D[j],D[pos]+L[pos,j])&lt;br /&gt;END;&lt;br /&gt;END;&lt;br /&gt;END&lt;br /&gt;END Dijkstra;&lt;br /&gt;&lt;br /&gt;La función Menor es la que calcula el mínimo de la expresión en recurrencia&lt;br /&gt;que define la solución del problema:&lt;br /&gt;&lt;br /&gt;PROCEDURE Menor(VAR D:SOLUCION; VAR S:MARCA; VAR pos:CARDINAL)&lt;br /&gt;:CARDINAL;&lt;br /&gt;VAR menor,i:CARDINAL;&lt;br /&gt;BEGIN&lt;br /&gt;menor:=MAX(CARDINAL); pos:=1;&lt;br /&gt;FOR i:=2 TO n DO&lt;br /&gt;IF NOT(S[i]) THEN&lt;br /&gt;IF D[i]&lt;menor then=""&gt;&lt;br /&gt;menor:=D[i]; pos:=i&lt;br /&gt;END&lt;br /&gt;END&lt;br /&gt;END;&lt;br /&gt;RETURN menor&lt;br /&gt;END Menor;&lt;br /&gt;&lt;br /&gt;La complejidad temporal del algoritmo es de orden O(n2), siendo de orden O(n) su complejidad espacial. No ganamos sustancialmente en eficiencia mediante el uso de esta técnica frente al planteamiento ávido del algoritmo, pero sin embargo sí ganamos en sencillez del diseño e implementación de la solución a partir del planteamiento del problema.&lt;br /&gt;&lt;/menor&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-745562490673270055?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/745562490673270055/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/06/sea-un-grafo-ponderado-g-va-donde-v-es.html#comment-form' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/745562490673270055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/745562490673270055'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/06/sea-un-grafo-ponderado-g-va-donde-v-es.html' title='EL ALGORITMO DE DIJKSTRA'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__9gdQlyIwfg/SiPpeb76cOI/AAAAAAAAACs/E6gmcRAWFSg/s72-c/Dibujo.bmp' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-4466171149554396053</id><published>2009-06-01T06:48:00.000-07:00</published><updated>2009-06-01T06:54:45.584-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Problemas de programación dinámica'/><title type='text'>El viajante de comercio</title><content type='html'>Se conocen las distancias entre un cierto número de ciudades. Un &lt;span style="font-weight: bold;"&gt;viajante&lt;/span&gt; debe, a partir de una de ellas, visitar cada ciudad exactamente una vez y regresar al punto de partida habiendo recorrido en total la menor distancia posible.&lt;br /&gt;Este problema consiste en encontrar el camino sin ciclos de menor peso de un grafo ponderado que recorra todos los vértices y vuelva al vértice original.&lt;br /&gt;Solución&lt;br /&gt;&lt;br /&gt;En primer lugar, vamos a plantear la solución del problema como una sucesión de decisiones que verifique el principio de óptimo. La idea va a consistir en construir una solución mediante la búsqueda sucesiva de recorridos mínimos de tamaño 1, 2, 3, etc.&lt;br /&gt;Representando el problema a través de un grafo g = (V,A), y siendo L su matriz de adyacencia, cada recorrido del viajante que parte del vértice v1 estará formado por un arco (v1,vk) para algún vértice vk perteneciente a V–{v1} y un camino de vk al vértice v1.&lt;br /&gt;Pero si el recorrido es óptimo también ha de ser óptimo el camino de vk al vértice v1, pues si no lo fuese llegaríamos a una contradicción. Si no lo fuese y existiera otro camino mejor, incluyendo a éste en el recorrido original obtendríamos un camino mejor que el óptimo, lo cual es imposible. Por tanto, se cumple el &lt;a href="http://webysw.blogspot.com/2009/05/principio-de-optimalidad-de-bellman.html"&gt;principio de óptimo&lt;/a&gt;.&lt;br /&gt;Planteemos entonces la relación en recurrencia. Para ello, llamaremos D(vi,S) a la longitud del camino mínimo que partiendo del vértice vi pasa por todos los vértices del conjunto S y vuelve al vértice vi. La solución al problema del viajante vendrá dada entonces por D(v1,V–{v1}):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/__9gdQlyIwfg/SiPc0HjEiQI/AAAAAAAAACU/jQzkfTEeem0/s1600-h/Dibujo.bmp"&gt;&lt;img style="cursor: pointer; width: 320px; height: 30px;" src="http://2.bp.blogspot.com/__9gdQlyIwfg/SiPc0HjEiQI/AAAAAAAAACU/jQzkfTEeem0/s320/Dibujo.bmp" alt="" id="BLOGGER_PHOTO_ID_5342356370928994562" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Generalizando para comenzar el recorrido desde cualquier vértice:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__9gdQlyIwfg/SiPdC0JzFlI/AAAAAAAAACk/koQfi08zXYY/s1600-h/Dibujo.bmp"&gt;&lt;img style="cursor: pointer; width: 320px; height: 66px;" src="http://4.bp.blogspot.com/__9gdQlyIwfg/SiPdC0JzFlI/AAAAAAAAACk/koQfi08zXYY/s320/Dibujo.bmp" alt="" id="BLOGGER_PHOTO_ID_5342356623420757586" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Obsérvese la diferencia que existe entre la estrategia de este algoritmo y los que tratamos de diseñar siguiendo dos técnicas ávidas (ver el problema 4.4 del capítulo anterior). En los algoritmos ávidos se ha de escoger una de las posibles opciones en cada paso, y una vez tomada –o descartada–, ya no vuelve a ser considerada nunca. Son algoritmos que no guardan “historia”, y por tanto no siempre funcionan. Sin embargo, en la Programación Dinámica la solución al problema total se va construyendo de otra forma: a partir de las soluciones óptimas para problemas más pequeños.&lt;br /&gt;No obstante, el diseño aquí realizado tiene un serio inconveniente: su implementación utilizando una estructura de datos que permita reutilizar los&lt;br /&gt;cálculos. Tal estructura debería contener las soluciones intermedias necesarias para el cómputo de D(v1,V–{v1}), pero estas son demasiadas.&lt;br /&gt;En efecto, la tabla debe tener n filas, y 2n columnas, pues éste es el cardinal de las partes del conjunto V, que son todas las posibilidades que puede tomar el segundo parámetro de D en su definición.&lt;br /&gt;Por tanto, sí existe una solución al problema del viajante utilizando Programación Dinámica, pero no sólo no consigue mejorar la eficiencia de su versión clásica mediante Vuelta Atrás (véase el siguiente capítulo), sino que tampoco ofrece una mejora en cuanto a la simplicidad de su implementación.&lt;br /&gt;&lt;br /&gt;Más información en &lt;a href="http://www.lcc.uma.es/%7Eav/Libro/CAP5.pdf"&gt;Programación Dinámica&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-4466171149554396053?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/4466171149554396053/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/06/el-viajante-de-comercio.html#comment-form' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/4466171149554396053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/4466171149554396053'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/06/el-viajante-de-comercio.html' title='El viajante de comercio'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/__9gdQlyIwfg/SiPc0HjEiQI/AAAAAAAAACU/jQzkfTEeem0/s72-c/Dibujo.bmp' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-8075974369034379419</id><published>2009-05-28T08:51:00.000-07:00</published><updated>2009-05-28T10:07:11.884-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conceptos de programación dinámica'/><title type='text'>Camino de coste mínimo en un grafo multietapa.</title><content type='html'>Un &lt;span style="font-weight: bold;"&gt;grafo &lt;/span&gt;multietapa G = {N, A} es un &lt;span style="font-weight: bold;"&gt;grafo&lt;/span&gt; dirigido en el que se puede hacer una partición del conjunto de nodos o vértices N en k(≥ 2) conjuntos disjuntos Ci , 1 ≤ i ≤ k, donde todo arco del &lt;span style="font-weight: bold;"&gt;grafo&lt;/span&gt; (n, m) es tal que n &lt;span style="font-size:78%;"&gt;pertenece a&lt;/span&gt; Ci y m &lt;span style="font-size:78%;"&gt;pertenece a&lt;/span&gt; Ci+1 para algún i, 1 ≤ i ≤ k − 1. El coste de cada arco (i, j) lo proporciona la función c. Los conjuntos C1 y Ck tienen un sólo nodo, llamándose al primero nodo origen (o) y al segundo nodo destino (d). Si el número de conjuntos Ci es k se dice que es un grafo k-etapa.&lt;br /&gt;El problema consiste en encontrar un &lt;span style="font-weight: bold;"&gt;camino de coste mínimo&lt;/span&gt; que vaya desde el nodo origen o al nodo destino d. Por las restricciones impuestas, un camino de coste mínimo tendrá exactamente un sólo nodo en cada conjunto Ci , de ahí que cada Ci deﬁna una etapa del grafo. También puede decirse que cada arco del camino une una etapa con la siguiente.&lt;br /&gt;Este problema tiene gran importancia en la práctica ya que muchos de los problemas de reparto óptimo de recursos pueden formularse en términos de un &lt;span style="font-weight: bold;"&gt;grafo&lt;/span&gt; multietapa.&lt;br /&gt;Veamos cómo aplicar programación dinámica a esta situación:&lt;br /&gt;Se satisface el principio de optimalidad ya que el camino de coste mínimo debe contener subcaminos de coste mínimo; en caso contrario, podrá sustituirse dichos subcaminos por otros mejores, resultando un camino total de coste menor. Además, la solución ﬁnal será una secuencia de decisiones, y cada decisión depende del resultado de otras. En general, la i-ésima decisión consiste en determinar, a partir de un nodo ni de Ci , un arco que tenga a ni como nodo origen y a algún ni+1 de Ci+1 como nodo destino, siendo 1 ≤ i ≤ k − 2. El número mínimo de decisiones para un grafo k-etapa es k − 2 ya que cada camino consta de k − 1 arcos, y el ultimo queda determinado por la decisión tomada en la etapa anterior.&lt;br /&gt;&lt;br /&gt;Sea CA(i, j) un camino de coste mínimo COST E(i, j) desde el nodo origen o hasta el nodo j de Ci . Usando una formulación hacia atrás tenemos&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/__9gdQlyIwfg/Sh65HljiOVI/AAAAAAAAAB0/PKtbn01gkiA/s1600-h/1.bmp"&gt;&lt;img style="cursor: pointer; width: 390px; height: 80px;" src="http://1.bp.blogspot.com/__9gdQlyIwfg/Sh65HljiOVI/AAAAAAAAAB0/PKtbn01gkiA/s320/1.bmp" alt="" id="BLOGGER_PHOTO_ID_5340909748099365202" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="file:///C:/DOCUME%7E1/AMB/CONFIG%7E1/Temp/moz-screenshot-3.jpg" alt="" /&gt;&lt;img src="file:///C:/DOCUME%7E1/AMB/CONFIG%7E1/Temp/moz-screenshot-4.jpg" alt="" /&gt;&lt;img src="file:///C:/DOCUME%7E1/AMB/CONFIG%7E1/Temp/moz-screenshot-5.jpg" alt="" /&gt;De igual forma, podemos analizar el coste mediante una formulación hacia adelante:&lt;br /&gt;Si CA(i, j) es un camino de coste mínimo COSTE(i, j) desde el nodo j del conjunto Ci hasta el nodo destino d , entonces:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/__9gdQlyIwfg/Sh65ZoL7GUI/AAAAAAAAAB8/Ypk0sJlh4cc/s1600-h/1.bmp"&gt;&lt;img style="cursor: pointer; width: 389px; height: 74px;" src="http://2.bp.blogspot.com/__9gdQlyIwfg/Sh65ZoL7GUI/AAAAAAAAAB8/Ypk0sJlh4cc/s320/1.bmp" alt="" id="BLOGGER_PHOTO_ID_5340910058043283778" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;En general, se podrán utilizar indistintamente cualquiera de las dos formulaciones. Veamos a continuación el algoritmo que nos permite construir la trayectoria de coste mínimo con una formulación hacia atrás. (Hemos suprimido el primer índice de la variable COSTE ya que considerábamos que no era trascendente para el algoritmo.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;algoritmo multigrafo (ENT A :arcos; k, n :entero; C :tabla[1..n,1..n]; SAL P :tabla[1..k])&lt;/span&gt;&lt;br /&gt;{Este algoritmo construye a partir de un grafo de k etapas, con n vértices,&lt;br /&gt;conjunto de arcos A y costes C, la trayectoria P de coste mínimo}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/__9gdQlyIwfg/Sh65yBWVUBI/AAAAAAAAACE/ZTm4uNN8KqQ/s1600-h/1.bmp"&gt;&lt;img style="cursor: pointer; width: 385px; height: 276px;" src="http://2.bp.blogspot.com/__9gdQlyIwfg/Sh65yBWVUBI/AAAAAAAAACE/ZTm4uNN8KqQ/s320/1.bmp" alt="" id="BLOGGER_PHOTO_ID_5340910477114691602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Para estudiar la complejidad de este algoritmo hay que tener en cuenta que la complejidad del primer bucle sera O(max(n, a)) = O(n + a) siendo n el número de vértices y a el número de aristas, y la del segundo O(k), donde k siempre es menor que n. Por tanto, la complejidad total del algoritmo es O(n + a).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-8075974369034379419?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/8075974369034379419/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/un-grafo-multietapa-g-n-es-un-grafo.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/8075974369034379419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/8075974369034379419'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/un-grafo-multietapa-g-n-es-un-grafo.html' title='Camino de coste mínimo en un grafo multietapa.'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__9gdQlyIwfg/Sh65HljiOVI/AAAAAAAAAB0/PKtbn01gkiA/s72-c/1.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-4554202538000142342</id><published>2009-05-21T06:41:00.000-07:00</published><updated>2009-05-21T14:06:54.223-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Funciones Java con programación dinámica'/><title type='text'>Función de Fibonacci</title><content type='html'>&lt;pre style ="background: #E9E9E9 url(http://neysitc.googlepages.com/bgcode.png) repeat-x ; border:#C90 dotted 1px; width:100%; text-align:justify; padding-left: 6px;padding-rigth: 6px;padding-top: 5px;"&gt;&lt;span&gt;&lt;a href="http://sistemasmen.blogspot.com"&gt;Codigo fuente&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;import java.io.*;&lt;br /&gt; &lt;br /&gt;public class Fibonacci {&lt;br /&gt;      BufferedReader teclado = new BufferedReader(new InputStreamReader(System.in));&lt;br /&gt;int opcionSalir;&lt;br /&gt;      public Fibonacci(){&lt;br /&gt;        mostrarMenu();&lt;br /&gt;      }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;public static long fibonacci_pd(long n) throws NumeroException {&lt;br /&gt;   if (n &amp;lt; 0) {&lt;br /&gt;       throw new NumeroException("No se pueden introducir números negativos");&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;  if(n==0 || n==1){&lt;br /&gt;      return n;&lt;br /&gt;  }&lt;br /&gt; long[] a=new long[(int)n+1];&lt;br /&gt; a[0]=0;&lt;br /&gt; a[1]=1;&lt;br /&gt; for(int i=2;i&amp;lt;=n;i++){&lt;br /&gt;   a[i]=a[i-1]+a[i-2];&lt;br /&gt; }&lt;br /&gt;  return a[(int)n];&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;  private void mostrarMenu() {&lt;br /&gt; &lt;br /&gt;    opcionSalir = 2;&lt;br /&gt; &lt;br /&gt;    int opcion;&lt;br /&gt;    do {&lt;br /&gt;      String[] menu = {&lt;br /&gt;          "\n-------------- Fibonacci --------------",&lt;br /&gt;          " 1.- Introducir valor",&lt;br /&gt; &lt;br /&gt;          "",&lt;br /&gt;          " 2.- Salir",&lt;br /&gt;          "----------------------------------------"};&lt;br /&gt; &lt;br /&gt;      for (int i = 0; i &amp;lt; menu.length; i++) {&lt;br /&gt;        System.out.println(menu[i]);&lt;br /&gt;      }&lt;br /&gt; &lt;br /&gt;      System.out.println();&lt;br /&gt;      opcion = pedirOpcion();&lt;br /&gt;      System.out.println();&lt;br /&gt;      procesarOpcion(opcion);&lt;br /&gt;      System.out.println();&lt;br /&gt;    }&lt;br /&gt;    while (opcion != opcionSalir);&lt;br /&gt;    System.out.println("Programa finalizado.");&lt;br /&gt; &lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  private void procesarOpcion(int opcion) {&lt;br /&gt;    switch (opcion) {&lt;br /&gt;      case 1:&lt;br /&gt;    calcular();&lt;br /&gt;        break;&lt;br /&gt; &lt;br /&gt;      case 2:&lt;br /&gt;        System.exit(0);&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  private int pedirOpcion() {&lt;br /&gt;    int opcion = 0;&lt;br /&gt;    do {&lt;br /&gt;      opcion = pedirEntero("Opcion: ");&lt;br /&gt;      if (opcion &amp;lt; 1 &amp;amp;&amp;amp; opcion &amp;gt; opcionSalir) {&lt;br /&gt;        System.out.println("Opcion inválida, repite");&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    while (opcion &amp;lt; 1 || opcion &amp;gt; opcionSalir);&lt;br /&gt;    return opcion;&lt;br /&gt;  }&lt;br /&gt;  private int pedirEntero(String mensaje) {&lt;br /&gt;  int entero = 0;&lt;br /&gt;  try {&lt;br /&gt;    System.out.print(mensaje);&lt;br /&gt;    entero = Integer.parseInt(teclado.readLine());&lt;br /&gt;  }&lt;br /&gt;  catch (IOException ex) {&lt;br /&gt;    System.out.println(&lt;br /&gt;        "Error generico de Entrada-Salida con el teclado");&lt;br /&gt;  }&lt;br /&gt;  catch (NumberFormatException ex) {&lt;br /&gt;    System.out.println("Formato erroneo para numero");&lt;br /&gt;  }&lt;br /&gt;  return entero;&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;public void calcular(){&lt;br /&gt;  System.out.println(&lt;br /&gt;          "\nIntroduzca el numero del que desea calcular la sucesión de Fibonacci: ");&lt;br /&gt; &lt;br /&gt;     &lt;br /&gt;        try {&lt;br /&gt;          long numero = Long.parseLong(teclado.readLine());&lt;br /&gt;          System.out.println(&lt;br /&gt;              "\nEl valor del la función de Fibonacci para el número " + numero +&lt;br /&gt;              " es: " + fibonacci_pd( numero));&lt;br /&gt;        }&lt;br /&gt;        catch (NumeroException ex) {&lt;br /&gt;          System.err.println("Solamente se puede introducir números");&lt;br /&gt; &lt;br /&gt;        }&lt;br /&gt;        catch (IOException ex) {&lt;br /&gt;            System.err.println(ex.getMessage());&lt;br /&gt;        }&lt;br /&gt;        catch (NumberFormatException ex) {&lt;br /&gt;                  System.err.println(ex.getMessage());&lt;br /&gt;        }&lt;br /&gt; }&lt;br /&gt;   &lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    new Fibonacci();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;CLASE NUMEROEXCEPTION&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;public class NumeroException extends Exception {&lt;br /&gt; &lt;br /&gt;public NumeroException(String mensaje) {&lt;br /&gt;  super(mensaje);&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Código anterior&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;import java.io.*;&lt;br /&gt; &lt;br /&gt;public class Fibonacci {&lt;br /&gt; &lt;br /&gt;  /**&lt;br /&gt;   * Función de fibonacci, se implementa con la técnica Programación Dinámica.&lt;br /&gt;   * Se comprueba que el número sea positivo.&lt;br /&gt;   * @param n long&lt;br /&gt;   * @throws NumeroException&lt;br /&gt;   * @return long&lt;br /&gt;   */&lt;br /&gt;  public static long fibonacci_pd(long n) throws NumeroException {&lt;br /&gt;    if (n &amp;lt; 0) {&lt;br /&gt;      throw new NumeroException("No se pueden introducir números negativos");&lt;br /&gt;    }&lt;br /&gt;    if (n == 0) {&lt;br /&gt;      throw new NumeroException("El número tiene que ser mayor que 0");&lt;br /&gt;    }&lt;br /&gt;    long[] f = new long[ (int) n + 1];&lt;br /&gt;    f[0] = 0;&lt;br /&gt;    f[1] = 1;&lt;br /&gt;    for (int i = 2; i &amp;lt; n + 1; i++) {&lt;br /&gt;      f[i] = f[i - 1] + f[i - 2];&lt;br /&gt;    }&lt;br /&gt;    return f[ (int) n];&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  /**&lt;br /&gt;   * Función Main. Se pide al usuario un número para calcular su valor mediante&lt;br /&gt;   * la función de Fibonacci&lt;br /&gt;   * @param args String[]&lt;br /&gt;   */&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));&lt;br /&gt;    System.out.println(&lt;br /&gt;        "\nIntroduzca el numero del que desea calcular la sucesión de Fibonacci: ");&lt;br /&gt;    try {&lt;br /&gt;      long numero = Long.parseLong(reader.readLine());&lt;br /&gt;      System.out.println(&lt;br /&gt;          "\nEl valor del la función de Fibonacci para el número " + numero +&lt;br /&gt;          " es: " + fibonacci_pd(numero));&lt;br /&gt;    }&lt;br /&gt;    catch (NumberFormatException nfe) {&lt;br /&gt;      System.err.println("Solamente se puede introducir números");&lt;br /&gt;      main(args);&lt;br /&gt;    }&lt;br /&gt;    catch (NumeroException ne) {&lt;br /&gt;      System.err.println(ne.getMessage());&lt;br /&gt;      main(args);&lt;br /&gt;    }&lt;br /&gt;    catch (IOException ioe) {&lt;br /&gt;      System.err.println(ioe.getMessage());&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Excepción usada en el codigo anterior&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;public class NumeroException&lt;br /&gt;    extends Exception {&lt;br /&gt; &lt;br /&gt;  public NumeroException(String mensaje) {&lt;br /&gt;    super(mensaje);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-4554202538000142342?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/4554202538000142342/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/funcion-de-fibonacci_21.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/4554202538000142342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/4554202538000142342'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/funcion-de-fibonacci_21.html' title='Función de Fibonacci'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-2659732380457598841</id><published>2009-05-21T06:00:00.000-07:00</published><updated>2009-05-21T14:09:38.323-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Problemas de programación dinámica'/><title type='text'>Función de Fibonacci con Programación Dinámica</title><content type='html'>Vamos a resolver la función de &lt;span style="font-weight: bold;"&gt;Fibonacci&lt;/span&gt; mediante &lt;span style="font-weight: bold;"&gt;programación dinámica&lt;/span&gt;, esta función como sabéis corresponde a la ecuación : f(x)= f(x-1) + f(x-2)&lt;br /&gt;&lt;br /&gt;Se puede realizar este problema mediante &lt;span style="font-weight: bold;"&gt;programación dinamica&lt;/span&gt; al igual que mediante divide y venceras, si bien es mas eficiente la resolución de &lt;span style="font-weight: bold;"&gt;programación dinamica&lt;/span&gt; para evitar calcular varias veces un mismo valor.&lt;br /&gt;&lt;br /&gt;La  precondición que presenta este problema es que no se puede buscar el valor de la función de &lt;span style="font-weight: bold;"&gt;fibonacci&lt;/span&gt; para numeros negativos.&lt;br /&gt;&lt;br /&gt;S&lt;span style="font-weight: bold;"&gt;olución al problema&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La solución que hemos dado al problema es un ejemplo del algoritmo de &lt;span style="font-weight: bold;"&gt;Programación dinamica&lt;/span&gt;, siendo esta implementacion una ligera mejora del ejemplo presentado en el cuaderno didactico de búsqueda recursivo "Función de &lt;span style="font-weight: bold;"&gt;Fibonacci&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Complejidad Temporal&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Este código contiene varias sentencias condicionales y varias instrucciones lineales, a la hora de hallar la complejidad temporal lo unico que nos interesa mirar es el unico bucle simple que hay. Teniendo en cuenta esto la complejidad temporal sería O(n) donde n es el numero de pasadas que tiene que realizar el bucle.&lt;br /&gt;&lt;br /&gt;Función de &lt;span style="font-weight: bold;"&gt;Fibonacci&lt;/span&gt; implementada con &lt;span style="font-weight: bold;"&gt;Programación Dinámica&lt;/span&gt; mediante Java:&lt;br /&gt;&lt;br /&gt;He encontrado esta implementación de clases que crea un programa que resuelve la función de &lt;span style="font-weight: bold;"&gt;Fibonacci&lt;/span&gt; mediante Java y &lt;span style="font-weight: bold;"&gt;programación dinámica&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;CLASE FIBONACCI&lt;/span&gt;&lt;br /&gt;&lt;pre style ="background: #E9E9E9 url(http://neysitc.googlepages.com/bgcode.png) repeat-x ; border:#C90 dotted 1px; width:100%; text-align:justify; padding-left: 6px;padding-rigth: 6px;padding-top: 5px;"&gt;&lt;span&gt;&lt;a href="http://sistemasmen.blogspot.com"&gt;Codigo fuente&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;import java.io.*;&lt;br /&gt; &lt;br /&gt;public class Fibonacci {&lt;br /&gt;      BufferedReader teclado = new BufferedReader(new InputStreamReader(System.in));&lt;br /&gt;int opcionSalir;&lt;br /&gt;      public Fibonacci(){&lt;br /&gt;        mostrarMenu();&lt;br /&gt;      }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;public static long fibonacci_pd(long n) throws NumeroException {&lt;br /&gt;   if (n &amp;lt; 0) {&lt;br /&gt;       throw new NumeroException("No se pueden introducir números negativos");&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;  if(n==0 || n==1){&lt;br /&gt;      return n;&lt;br /&gt;  }&lt;br /&gt; long[] a=new long[(int)n+1];&lt;br /&gt; a[0]=0;&lt;br /&gt; a[1]=1;&lt;br /&gt; for(int i=2;i&amp;lt;=n;i++){&lt;br /&gt;   a[i]=a[i-1]+a[i-2];&lt;br /&gt; }&lt;br /&gt;  return a[(int)n];&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;  private void mostrarMenu() {&lt;br /&gt; &lt;br /&gt;    opcionSalir = 2;&lt;br /&gt; &lt;br /&gt;    int opcion;&lt;br /&gt;    do {&lt;br /&gt;      String[] menu = {&lt;br /&gt;          "\n-------------- Fibonacci --------------",&lt;br /&gt;          " 1.- Introducir valor",&lt;br /&gt; &lt;br /&gt;          "",&lt;br /&gt;          " 2.- Salir",&lt;br /&gt;          "----------------------------------------"};&lt;br /&gt; &lt;br /&gt;      for (int i = 0; i &amp;lt; menu.length; i++) {&lt;br /&gt;        System.out.println(menu[i]);&lt;br /&gt;      }&lt;br /&gt; &lt;br /&gt;      System.out.println();&lt;br /&gt;      opcion = pedirOpcion();&lt;br /&gt;      System.out.println();&lt;br /&gt;      procesarOpcion(opcion);&lt;br /&gt;      System.out.println();&lt;br /&gt;    }&lt;br /&gt;    while (opcion != opcionSalir);&lt;br /&gt;    System.out.println("Programa finalizado.");&lt;br /&gt; &lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  private void procesarOpcion(int opcion) {&lt;br /&gt;    switch (opcion) {&lt;br /&gt;      case 1:&lt;br /&gt;    calcular();&lt;br /&gt;        break;&lt;br /&gt; &lt;br /&gt;      case 2:&lt;br /&gt;        System.exit(0);&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  private int pedirOpcion() {&lt;br /&gt;    int opcion = 0;&lt;br /&gt;    do {&lt;br /&gt;      opcion = pedirEntero("Opcion: ");&lt;br /&gt;      if (opcion &amp;lt; 1 &amp;amp;&amp;amp; opcion &amp;gt; opcionSalir) {&lt;br /&gt;        System.out.println("Opcion inválida, repite");&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    while (opcion &amp;lt; 1 || opcion &amp;gt; opcionSalir);&lt;br /&gt;    return opcion;&lt;br /&gt;  }&lt;br /&gt;  private int pedirEntero(String mensaje) {&lt;br /&gt;  int entero = 0;&lt;br /&gt;  try {&lt;br /&gt;    System.out.print(mensaje);&lt;br /&gt;    entero = Integer.parseInt(teclado.readLine());&lt;br /&gt;  }&lt;br /&gt;  catch (IOException ex) {&lt;br /&gt;    System.out.println(&lt;br /&gt;        "Error generico de Entrada-Salida con el teclado");&lt;br /&gt;  }&lt;br /&gt;  catch (NumberFormatException ex) {&lt;br /&gt;    System.out.println("Formato erroneo para numero");&lt;br /&gt;  }&lt;br /&gt;  return entero;&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;public void calcular(){&lt;br /&gt;  System.out.println(&lt;br /&gt;          "\nIntroduzca el numero del que desea calcular la sucesión de Fibonacci: ");&lt;br /&gt; &lt;br /&gt;     &lt;br /&gt;        try {&lt;br /&gt;          long numero = Long.parseLong(teclado.readLine());&lt;br /&gt;          System.out.println(&lt;br /&gt;              "\nEl valor del la función de Fibonacci para el número " + numero +&lt;br /&gt;              " es: " + fibonacci_pd( numero));&lt;br /&gt;        }&lt;br /&gt;        catch (NumeroException ex) {&lt;br /&gt;          System.err.println("Solamente se puede introducir números");&lt;br /&gt; &lt;br /&gt;        }&lt;br /&gt;        catch (IOException ex) {&lt;br /&gt;            System.err.println(ex.getMessage());&lt;br /&gt;        }&lt;br /&gt;        catch (NumberFormatException ex) {&lt;br /&gt;                  System.err.println(ex.getMessage());&lt;br /&gt;        }&lt;br /&gt; }&lt;br /&gt;   &lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    new Fibonacci();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;CLASE NUMEROEXCEPTION&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;public class NumeroException extends Exception {&lt;br /&gt; &lt;br /&gt;public NumeroException(String mensaje) {&lt;br /&gt;  super(mensaje);&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Código anterior&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;import java.io.*;&lt;br /&gt; &lt;br /&gt;public class Fibonacci {&lt;br /&gt; &lt;br /&gt;  /**&lt;br /&gt;   * Función de fibonacci, se implementa con la técnica Programación Dinámica.&lt;br /&gt;   * Se comprueba que el número sea positivo.&lt;br /&gt;   * @param n long&lt;br /&gt;   * @throws NumeroException&lt;br /&gt;   * @return long&lt;br /&gt;   */&lt;br /&gt;  public static long fibonacci_pd(long n) throws NumeroException {&lt;br /&gt;    if (n &amp;lt; 0) {&lt;br /&gt;      throw new NumeroException("No se pueden introducir números negativos");&lt;br /&gt;    }&lt;br /&gt;    if (n == 0) {&lt;br /&gt;      throw new NumeroException("El número tiene que ser mayor que 0");&lt;br /&gt;    }&lt;br /&gt;    long[] f = new long[ (int) n + 1];&lt;br /&gt;    f[0] = 0;&lt;br /&gt;    f[1] = 1;&lt;br /&gt;    for (int i = 2; i &amp;lt; n + 1; i++) {&lt;br /&gt;      f[i] = f[i - 1] + f[i - 2];&lt;br /&gt;    }&lt;br /&gt;    return f[ (int) n];&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  /**&lt;br /&gt;   * Función Main. Se pide al usuario un número para calcular su valor mediante&lt;br /&gt;   * la función de Fibonacci&lt;br /&gt;   * @param args String[]&lt;br /&gt;   */&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));&lt;br /&gt;    System.out.println(&lt;br /&gt;        "\nIntroduzca el numero del que desea calcular la sucesión de Fibonacci: ");&lt;br /&gt;    try {&lt;br /&gt;      long numero = Long.parseLong(reader.readLine());&lt;br /&gt;      System.out.println(&lt;br /&gt;          "\nEl valor del la función de Fibonacci para el número " + numero +&lt;br /&gt;          " es: " + fibonacci_pd(numero));&lt;br /&gt;    }&lt;br /&gt;    catch (NumberFormatException nfe) {&lt;br /&gt;      System.err.println("Solamente se puede introducir números");&lt;br /&gt;      main(args);&lt;br /&gt;    }&lt;br /&gt;    catch (NumeroException ne) {&lt;br /&gt;      System.err.println(ne.getMessage());&lt;br /&gt;      main(args);&lt;br /&gt;    }&lt;br /&gt;    catch (IOException ioe) {&lt;br /&gt;      System.err.println(ioe.getMessage());&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Excepción usada en el codigo anterior&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;public class NumeroException&lt;br /&gt;    extends Exception {&lt;br /&gt; &lt;br /&gt;  public NumeroException(String mensaje) {&lt;br /&gt;    super(mensaje);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-2659732380457598841?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/2659732380457598841/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/funcion-de-fibonacci-con-programacion.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/2659732380457598841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/2659732380457598841'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/funcion-de-fibonacci-con-programacion.html' title='Función de Fibonacci con Programación Dinámica'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-891747871379221676</id><published>2009-05-12T04:23:00.001-07:00</published><updated>2009-05-12T04:32:11.509-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Funciones Java con programación dinámica'/><title type='text'>Problema de la moneda con programación dinámica</title><content type='html'>&lt;pre&gt;&lt;br /&gt;public int[][] Mochila(int[] pesos, int[] beneficios, int capacidad){&lt;br /&gt; &lt;br /&gt;   //Creamos la matriz de devoluciones&lt;br /&gt;   int[][]  matriz_mochila = new int[pesos.length+1][capacidad+1];&lt;br /&gt;&lt;br /&gt;  //Rellenamos la 1ª fila de ceros&lt;br /&gt;  for(int i = 0; i &lt;= capacidad; i++) &lt;br /&gt;    matriz_mochila[0][i] = 0;       &lt;br /&gt;  //Rellenamos la 1ª columna de ceros  &lt;br /&gt;  for(int i = 0; i &lt;= pesos.length; i++)     &lt;br /&gt;     matriz_mochila[i][0] = 0;      &lt;br /&gt;&lt;br /&gt;  for(int j = 1; j &lt;= pesos.length ; j++) &lt;br /&gt;    for(int c = 1; c &lt;= capacidad; c++){   &lt;br /&gt;        if(c &lt;  pesos[j-1] ){           &lt;br /&gt;          matriz_mochila[j][c] = matriz_mochila[j-1][c];     &lt;br /&gt;        }else{&lt;br /&gt;          if(matriz_mochila[j-1][c] &gt; matriz_mochila[j-1][c-pesos[j-1]]+ beneficios[j-1]){&lt;br /&gt;             matriz_mochila[j][c] = matriz_mochila[j-1][c];&lt;br /&gt;          }else{&lt;br /&gt;             matriz_mochila[j][c] = matriz_mochila[j-1][c-pesos[j-1]]+beneficios[j-1];&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;     }&lt;br /&gt;   return matriz_mochila;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-891747871379221676?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/891747871379221676/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/problema-de-la-moneda-con-programacion.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/891747871379221676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/891747871379221676'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/problema-de-la-moneda-con-programacion.html' title='Problema de la moneda con programación dinámica'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-317485481046022849</id><published>2009-05-11T13:32:00.000-07:00</published><updated>2009-05-11T13:41:34.887-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Libros sobre Programación Dinámica'/><title type='text'>Libros sobre Programación Dinámica</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__9gdQlyIwfg/SgiMwDkprpI/AAAAAAAAABc/dXYWrimxkE8/s1600-h/8436236882.jpg"&gt;&lt;img style="padding: 4px; cursor: pointer; float: left; width: 85px; height: 118px;" src="http://4.bp.blogspot.com/__9gdQlyIwfg/SgiMwDkprpI/AAAAAAAAABc/dXYWrimxkE8/s320/8436236882.jpg" alt="" id="BLOGGER_PHOTO_ID_5334668515840994962" border="0" /&gt;&lt;/a&gt;&lt;span style=""&gt;&lt;span style="font-family:B Garamond Bold;"&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Teoría de colas y programación dinámica&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:B Garamond Bold;"&gt;Autora:&lt;/span&gt;&lt;span style="font-family:Garamond;"&gt; Isabel Plaza Idalgo.&lt;/span&gt;&lt;/span&gt;  &lt;/p&gt; 75 págs. / Rústica / Castellano / Libro&lt;br /&gt;        ISBN10 8436236882; ISBN13 9788436236880&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Fundamentos de Programación Lineal y Optimización en Redes: Ejercicios Resueltos de Investigación Operativa Asistidos por Ordenador&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;Autor:David Pujolar Morales(Universidad Autónoma de Barcelona. Servicio de Publicaciones = Universitat Autònoma de Barcelona. Servei de Publicacions)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-317485481046022849?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/317485481046022849/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/libros-sobre-programacion-dinamica.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/317485481046022849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/317485481046022849'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/libros-sobre-programacion-dinamica.html' title='Libros sobre Programación Dinámica'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__9gdQlyIwfg/SgiMwDkprpI/AAAAAAAAABc/dXYWrimxkE8/s72-c/8436236882.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-7963460919548319700</id><published>2009-05-11T08:07:00.000-07:00</published><updated>2009-05-12T04:28:23.790-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Problemas de programación dinámica'/><title type='text'>Problema de la mochila con programación dinámica</title><content type='html'>Sea n objetos no fraccionables de pesos pi y beneficios bi. El peso máximo que puede llevar la mochila es C. Queremos llenar la &lt;span style="font-weight: bold;"&gt;mochila&lt;/span&gt; con objetos, de forma que se maximice el beneficio.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Datos &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;* n objetos con pesos pi y beneficios bi asociados a cada objeto.&lt;br /&gt;* No se pueden fraccionar los objetos (se cogen o no se cogen).&lt;br /&gt;* Se define un problema más general en función del número de objetos y la capacidad C de la &lt;span style="font-weight: bold;"&gt;mochila&lt;/span&gt;: mochila(k,l,C)&lt;br /&gt;* Resolver el &lt;span style="font-weight: bold;"&gt;problema&lt;/span&gt; consiste en obtener: mochila(1,n,C)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Resolución mediante Programación Dinámica &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Para resolver el &lt;span style="font-weight: bold;"&gt;problema de la mochila &lt;/span&gt;necesitamos realizar ciertas acciones:&lt;br /&gt;&lt;br /&gt;* Ver que se cumple el principio de optimalidad de Bellman.&lt;br /&gt;* Buscar ecuaciones recurrentes para el &lt;span style="font-weight: bold;"&gt;problema&lt;/span&gt;.&lt;br /&gt;* Construir una tabla de valores a partir de las ecuaciones.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Principio de optimalidad de Bellman&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;* Cualquier subsecuencia de decisiones de una secuencia óptima de decisiones que resuelve un &lt;span style="font-weight: bold;"&gt;problema&lt;/span&gt; también debe ser óptima respecto al subproblema que se resuelve.&lt;br /&gt;* Sea y1,…,yn una secuencia óptima de valores 0-1 para x1,…,xn.&lt;br /&gt;o Si y1=0, entonces y2,…,yn forman una secuencia óptima para el &lt;span style="font-weight: bold;"&gt;problema mochila&lt;/span&gt;(2, n, C).&lt;br /&gt;o Si y1=1, entonces y2,…,yn forman una secuencia óptima para el &lt;span style="font-weight: bold;"&gt;problema mochila&lt;/span&gt;(2, n, C - p1).&lt;br /&gt;&lt;br /&gt;* Demostración: Si existe una solución mejor para el &lt;span style="font-weight: bold;"&gt;problema&lt;/span&gt; correspondiente, entonces es mejor que para el &lt;span style="font-weight: bold;"&gt;problema mochila&lt;/span&gt;(1, n, C), en contra de la hipótesis. Lo mismo se cumple en cualquier etapa de decisión.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ecuaciones recurrentes para el problema &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;a) Ecuación hacia delante&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;* Supongamos que gi(C) es el beneficio acumulado para la solución óptima del &lt;span style="font-weight: bold;"&gt;problema mochila&lt;/span&gt;(j,n,C), entonces:&lt;br /&gt;&lt;br /&gt;gj(C)= max {gj+1(C), gj+1(C-pj)+bj}&lt;br /&gt;&lt;br /&gt;cuyo significado:&lt;br /&gt;&lt;br /&gt;gj+1(C) -&gt; no se coge el objeto j&lt;br /&gt;gj+1(C-pj)+bj -&gt; se coge el objeto j&lt;br /&gt;&lt;br /&gt;* El caso trivial se da cuando j vale n+1, y en este caso:&lt;br /&gt;&lt;br /&gt;gn+1(C) = 0&lt;br /&gt;&lt;br /&gt;* Luego el cálculo de &lt;span style="font-weight: bold;"&gt;mochila&lt;/span&gt;(1,n,C) se reduce a la aplicación de las ecuaciones:&lt;br /&gt;&lt;br /&gt;gj(C) = max  {gj+1(C), gj+1(C-pj)+bj} si j&lt;&gt;n+1&lt;br /&gt;gj(C) = 0 si j = n+1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;b) Ecuación hacia atrás&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;* Supongamos que gj(C) es el beneficio acumulado para la solución óptima del &lt;span style="font-weight: bold;"&gt;problema mochila&lt;/span&gt;(1,j,C), entonces:&lt;br /&gt;&lt;br /&gt;gj(C)= max {gj-1(C), gj-1(C-pj)+bj}&lt;br /&gt;&lt;br /&gt;cuyo significado:&lt;br /&gt;&lt;br /&gt;gj-1(C) -&gt; no se coge el objeto j&lt;br /&gt;gj-1(C-pj)+bj -&gt; se coge el objeto j&lt;br /&gt;&lt;br /&gt;* El caso trivial se da cuando j vale 0, y en este caso:&lt;br /&gt;&lt;br /&gt;g0(C) = 0&lt;br /&gt;&lt;br /&gt;* Luego el cálculo de &lt;span style="font-weight: bold;"&gt;mochila&lt;/span&gt;(1,n,C) se reduce a la aplicación de las ecuaciones:&lt;br /&gt;&lt;br /&gt;gj(C) = max  {gj-1(C), gj-1(C-pj)+bj} si j&lt;&gt;0&lt;br /&gt;gj(C) = 0 si j = 0&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Implementación&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;* Si consideramos la ecuación hacia atrás, la implementación nos quedará:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;proc mochila(p,b:vector[1..n] de nat,cap: nat,g: vector[0..n, 0..cap] de nat)&lt;br /&gt;var c,j: nat;&lt;br /&gt;para c=0 hasta cap hacer g[0,c]=0 fpara;&lt;br /&gt;para j=1 hasta n hacer g[j,0]=0 fpara;&lt;br /&gt;para j=1 hasta n hacer&lt;br /&gt;para c=1 hasta cap hacer&lt;br /&gt;si c menor que  p[j] entonces&lt;br /&gt;g[j,c]=g[j-1,c];&lt;br /&gt;en caso contrario&lt;br /&gt;si g[j-1,c] mayor  que g[j-1,c-p[j]]+b[j] entonces&lt;br /&gt;   g[j,c]=g[j-1,c];            &lt;br /&gt;en caso contrario&lt;br /&gt;   g[j,c]=g[j-1,c-p[j]]+b[j];&lt;br /&gt;fsi;&lt;br /&gt;fsi;&lt;br /&gt;fpara;&lt;br /&gt;fpara;&lt;br /&gt;fproc;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Función Java del problema de la mochila&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; public int[][] Mochila(int[] pesos, int[] beneficios, int capacidad){&lt;br /&gt;   &lt;br /&gt;    //Creamos la matriz de devoluciones&lt;br /&gt;    int[][]  matriz_mochila = new int[pesos.length+1][capacidad+1];&lt;br /&gt;&lt;br /&gt;   //Rellenamos la 1ª fila de ceros&lt;br /&gt;   for(int i = 0; i &lt;= capacidad; i++)&lt;br /&gt;            matriz_mochila[0][i] = 0; &lt;br /&gt;&lt;br /&gt;   //Rellenamos la 1ª columna de ceros&lt;br /&gt;   for(int i = 0; i &lt;= pesos.length; i++)  &lt;br /&gt;           matriz_mochila[i][0] = 0;   &lt;br /&gt;&lt;br /&gt;        for(int j = 1; j &lt;= pesos.length ; j++)  &lt;br /&gt;           for(int c = 1; c &lt;= capacidad; c++){  &lt;br /&gt;      if(c &lt;  pesos[j-1] ){   &lt;br /&gt;        matriz_mochila[j][c] = matriz_mochila[j-1][c]; &lt;br /&gt;            }else{   &lt;br /&gt;              if(matriz_mochila[j-1][c] &gt; matriz_mochila[j-1][c-pesos[j-1]]+ beneficios[j-1]){&lt;br /&gt;           matriz_mochila[j][c] = matriz_mochila[j-1][c];&lt;br /&gt;               }else{&lt;br /&gt;                 matriz_mochila[j][c] = matriz_mochila[j-1][c-pesos[j-1]]+beneficios[j-1];&lt;br /&gt;               }&lt;br /&gt;            }&lt;br /&gt;       }&lt;br /&gt;       return matriz_mochila;&lt;br /&gt;     }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-7963460919548319700?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/7963460919548319700/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/pro.html#comment-form' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/7963460919548319700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/7963460919548319700'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/pro.html' title='Problema de la mochila con programación dinámica'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-3306701083639347199</id><published>2009-05-11T02:41:00.000-07:00</published><updated>2009-05-11T03:17:47.612-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conceptos de programación dinámica'/><title type='text'>Principio de optimalidad de Bellman</title><content type='html'>En este contexto, "optimizar" equivale a seleccionar (buscar) la "mejor" solución de entre muchas posibles alternativas. Este proceso de optimización puede ser visto como una secuencia de decisiones que nos proporcionan la solución correcta. Si, dada una subsecuencia de decisiones,&lt;br /&gt;siempre se conoce cual es la decisión que debe tomarse a continuación para obtener la secuencia óptima, el problema es elemental y se resuelve trivialmente tomando una decisión detrás de otra, lo que se conoce como estrategia voraz.&lt;br /&gt;&lt;br /&gt;A menudo, aunque no sea posible aplicar la estrategia voraz, se cumple el principio de optimalidad de Bellman : "dada una secuencia óptima de decisiones, toda subsecuencia de ella es, a su vez, óptima". En este caso sigue siendo posible el ir tomando decisiones elementales, en la&lt;br /&gt;confianza de que la combinación de ellas seguirá siendo óptima, pero será entonces necesario explorar muchas secuencias de decisiones para dar con la correcta, siendo aquí donde interviene la programación dinámica.&lt;br /&gt;&lt;br /&gt;Contemplar un problema como una secuencia de decisiones equivale a dividirlo en subproblemas de talla inferior, en principio más fácilmente resolubles. Ello se enmarca en el método de Divide y Vencerás, técnica similar a la de Programación Dinámica. La programación dinámica se aplica cuando la subdivisión de un problema conduce a:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Una enorme cantidad de subproblemas.&lt;/li&gt;&lt;li&gt; Subproblemas cuyas soluciones parciales se solapan.&lt;/li&gt;&lt;li&gt; Grupos de subproblemas de muy distinta complejidad.&lt;/li&gt;&lt;/ul&gt;circunstancias que en conjunto o por separado, llevarían a una complejidad exponencial de la estrategia "Divide y Vencerás".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-3306701083639347199?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/3306701083639347199/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/principio-de-optimalidad-de-bellman.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/3306701083639347199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/3306701083639347199'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/principio-de-optimalidad-de-bellman.html' title='Principio de optimalidad de Bellman'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-1501458621483169693</id><published>2009-05-07T03:18:00.000-07:00</published><updated>2009-05-07T03:19:01.355-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conceptos de programación dinámica'/><title type='text'>Proceso de resolución de problemas de programación dinámica</title><content type='html'>En general el problema se puede usando  un  proceso de tres pasos:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Separar el problema en subproblemas más pequeños.&lt;/li&gt;&lt;li&gt; Resolver estos problemas óptimamente usando  este proceso de tres pasos de manera recursiva.&lt;/li&gt;&lt;li&gt; Use las soluciones optimas para construir una solución óptima del problema original.&lt;/li&gt;&lt;/ul&gt;Los subproblemas  son así mismo  resueltos dividiendo estos en subproblemas  y así en adelante hasta que se alcance el caso más simple que sea fácil de resolver.&lt;br /&gt;&lt;br /&gt;Decir que un problema tiene subproblemas sobrepuestos es decir que un mismo subproblema es usado para resolver muchos problemas diferentes&lt;br /&gt;más grandes.&lt;br /&gt;&lt;br /&gt;Por ejemplo en la secuencia de Fibonacci F3 = F1 + F2 y F4 = F2 + F3, el calculo de cada número involucra el cálculo de F2. Ya que ambos F3 y F4 son necesarios para calcular F5, un método ingenuo para calcular F5 puede terminar haciendo el calculo de F2 dos o más veces.&lt;br /&gt;&lt;br /&gt;Cuando los subproblemas se sobreponen un método puede perder tiempo recalculando soluciones óptimas de subproblemas ya resueltos.&lt;br /&gt;&lt;br /&gt;A fin de evitar la repetición de cálculos, se pueden  guardar las soluciones a los problemas ya resueltos de manera que si se requiere resolver el mismo problema después, se puede reutilizar los cálculos&lt;br /&gt;hechos previamente.&lt;br /&gt;&lt;br /&gt;Este approach es llamado memoización (no memorización).&lt;br /&gt;&lt;br /&gt;Cuando se este seguro de que una solución particular ya no se necesita más se puede entonces borrarla,  liberando así el espacio.&lt;br /&gt;&lt;br /&gt;En algunos casos se pueden hacer cómputos que se saben se requerirán en lo posterior.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-1501458621483169693?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/1501458621483169693/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/proceso-de-resolucion-de-problemas-de.html#comment-form' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/1501458621483169693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/1501458621483169693'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/proceso-de-resolucion-de-problemas-de.html' title='Proceso de resolución de problemas de programación dinámica'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-8804379884660188968</id><published>2009-05-07T03:11:00.000-07:00</published><updated>2009-05-07T03:25:33.851-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conceptos de programación dinámica'/><title type='text'>Subestructura óptima y subproblemas sobrepuestos</title><content type='html'>Subestructura óptima significa que la&lt;span style="font-weight: bold;"&gt; subestructura de los subproblemas&lt;/span&gt; puede ser   usada para encontrar la solución óptima para&lt;br /&gt;el problema completo.&lt;br /&gt;&lt;br /&gt;Por ejemplo, el camino más corto a un objetivo desde un vértice, en un grafo acíclico puede ser encontrado calculando inicialmente el camino más cercano al objetivo desde todos los vértices adyacentes y entonces&lt;br /&gt;usando esto para encontrar el mejor camino completo.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__9gdQlyIwfg/SgKy6JUXdMI/AAAAAAAAABU/TQpC6HdxFbY/s1600-h/subestructura-optima.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 182px;" src="http://4.bp.blogspot.com/__9gdQlyIwfg/SgKy6JUXdMI/AAAAAAAAABU/TQpC6HdxFbY/s320/subestructura-optima.jpg" alt="" id="BLOGGER_PHOTO_ID_5333021620763587778" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Figura 1.&lt;/span&gt; Encontrando el camino más  cercano en un grafo usando &lt;span style="font-weight: bold;"&gt;subestructuras optimas&lt;/span&gt;; las líneas oscuras indican el camino  más cercano entre el inicio y el objetivo.&lt;br /&gt;&lt;br /&gt;Decir que un problema tiene &lt;span style="font-weight: bold;"&gt;subproblemas sobrepuestos&lt;/span&gt; es decir que un mismo subproblema es usado para resolver muchos problemas diferentes más grandes.&lt;br /&gt;&lt;a href="http://webysw.blogspot.com/2009/05/proceso-de-resolucion-de-problemas-de.html" title="Resolución de problemas de programación dinámica" alt="Resolución de problemas de programación dinámica"&gt;&lt;br /&gt;Resolución de problemas de programación dinámica&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-8804379884660188968?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/8804379884660188968/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/subestructura-optima-y-subproblemas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/8804379884660188968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/8804379884660188968'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/subestructura-optima-y-subproblemas.html' title='Subestructura óptima y subproblemas sobrepuestos'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/__9gdQlyIwfg/SgKy6JUXdMI/AAAAAAAAABU/TQpC6HdxFbY/s72-c/subestructura-optima.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-8940071682242537864</id><published>2009-05-05T22:59:00.000-07:00</published><updated>2009-05-05T23:10:39.709-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Funciones Java con programación dinámica'/><title type='text'>El problema de las monedas con programación dinámica.</title><content type='html'>Solucionemos este &lt;span style="font-weight: bold;"&gt;problema de programación dinámica&lt;/span&gt; en una función Java:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public int Minima_devolucion(int cantidad_devuelta, int[]  monedas){&lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  //Creamos la matriz de devoluciones&lt;br /&gt;  int[][]  matriz_cambio = new int[monedas.length+1][cantidad_devuelta+1];&lt;br /&gt;  &lt;br /&gt; //Rellenamos la 1ª columna de ceros&lt;br /&gt; for(int i = 0; i &lt; monedas.length; i++)&lt;br /&gt;     matriz_cambio[i][0] = 0;&lt;br /&gt;  &lt;br /&gt; //La 1ª fila menos la 1ª columna un número alto&lt;br /&gt; for(int j = 1; j &lt;= cantidad_devuelta; j++)&lt;br /&gt;     matriz_cambio[0][j] = 999999;&lt;br /&gt;  &lt;br /&gt; for(int i = 1; i &lt;= monedas.length ; i++)&lt;br /&gt;    for(int j = 1; j &lt;= cantidad_devuelta; j++){&lt;br /&gt;     if(monedas[i-1] &gt; j ){&lt;br /&gt;       //Si la moneda es superior a la cantidad a devolver&lt;br /&gt;       matriz_cambio[i][j] = matriz_cambio[i-1][j]; &lt;br /&gt;     }else{&lt;br /&gt;       //Si la moneda no es superior a la cantidad a devolver&lt;br /&gt;     &lt;br /&gt;       //Calcular cual es el mínimo de estas dos posiciones&lt;br /&gt;       int minimo = 0; //Guardaremos aquí el mínimo&lt;br /&gt;     &lt;br /&gt;      if(matriz_cambio[i-1][j] &lt; matriz_cambio[i][j - monedas[i-1]] + 1){&lt;br /&gt;        minimo = matriz_cambio[i-1][j];&lt;br /&gt;      }else{&lt;br /&gt;        minimo = matriz_cambio[i][j - monedas[i-1]] + 1;&lt;br /&gt;      }&lt;br /&gt;      //Guardamos mínimo&lt;br /&gt;      matriz_cambio[i][j] = minimo;&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt; return matriz_cambio[monedas.length][cantidad_devuelta];&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-8940071682242537864?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/8940071682242537864/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/el-problema-de-las-monedas-con.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/8940071682242537864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/8940071682242537864'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/el-problema-de-las-monedas-con.html' title='El problema de las monedas con programación dinámica.'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-8268670659864651739</id><published>2009-05-05T03:26:00.000-07:00</published><updated>2009-05-05T23:11:22.826-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Problemas de programación dinámica'/><title type='text'>Problema de las monedas con programación dinámica</title><content type='html'>Para el problema de las monedas con &lt;span style="font-weight: bold;"&gt;programación dinámica&lt;/span&gt; se necesita crear un algoritmo que permita a una máquina expendedora devolver el cambio mediante el menor número de monedas posible. Mediante la programación dinámica se solucionará el caso en el que el número de monedas de cada tipo es ilimitado. En el &lt;span style="font-weight: bold;"&gt;problema de las monedas&lt;/span&gt; mediante el algoritmo voraz el que el número de monedas es ilimitado.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Descripción &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Supongamos que se tienen monedas de valor 1, 4 y 6 y que se debe devolver una cantidad correspondiente al valor 8. Siguiendo el método de la &lt;span style="font-weight: bold;"&gt;programación dinámica&lt;/span&gt;, se rellenará una tabla con las filas correspondientes a cada valor para las monedas y las columnas con valores desde el 1 hasta el 8. Cada posición (i, j) de la tabla nos indica el número mínimo de monedas requeridas para devolver la cantidad j con monedas con valor menor o igual al de i:&lt;br /&gt;&lt;br /&gt;____ 1     2     3     4     5     6     7     8&lt;br /&gt;m1=1     1     2     3     4     5     6     7     8&lt;br /&gt;m2=4     1     2     3     1     2     3     4     2&lt;br /&gt;m3=6     1     2     3     1     2     1     2     2&lt;br /&gt;&lt;br /&gt;Ejemplo para la posición i = 2 y j = 7, se requiere una moneda tipo 2 con valor 4 y tres monedas de tipo 1 con valor uno, por lo tanto en la tabla el número de monedas en la posición (2,7) sera 1 + 3 = 4.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Algoritmo &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1. Para cada casilla de la tabla hacer:&lt;br /&gt;2. Si el valor de la moneda actual es mayor que la cantidad, se paga con el resto de monedas, es decir, se toma el resultado de la casilla superior.&lt;br /&gt;3. Si el valor de la moneda actual es menor o igual que la cantidad, se toma el mínimo entre:&lt;br /&gt;   1. Pagar con el resto de monedas, tomando el resultado de la casilla superior.&lt;br /&gt;   2. Pagar con una moneda del tipo actual y el resto con el resultado que se hubiera obtenido al pagar la cantidad actual a la que se le ha restado el valor de la moneda actual.&lt;br /&gt;4. Tomar como resultado el valor de la última celda.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Pseudocódigo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Solucionemos este &lt;span style="font-weight: bold;"&gt;problema de programación dinámica&lt;/span&gt; en un pseudocódigo.&lt;br /&gt;&lt;br /&gt;Como parámetros de entrada, la función toma C, que corresponde con la cantidad a devolver, y un vector M de monedas, que almacena el valor de cada tipo. Devuelve num, el número de monedas necesarias para realizar la devolución.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;fun cambio (C: nat; M[1..n] de nat) dev num: nat&lt;br /&gt;var&lt;br /&gt; T[0..n][0..C] de nat&lt;br /&gt;begin&lt;br /&gt; T[0][1..C] := \infty;&lt;br /&gt; T[1..n][0] := 0;&lt;br /&gt; para i := 1 hasta n hacer&lt;br /&gt;     para j := 1 hasta C hacer&lt;br /&gt;         si M[i] &gt; j entonces T[i, j] := T[i-1, j]&lt;br /&gt;             si no&lt;br /&gt;                 T[i, j] := min {T[i-1, j], T[i, j-M[i] ] + 1 }&lt;br /&gt;             fsi&lt;br /&gt;     fpara&lt;br /&gt; fpara&lt;br /&gt; num := T[n, C]&lt;br /&gt;ffun&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Código Java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Solucionemos este &lt;span style="font-weight: bold;"&gt;problema de programación dinámica&lt;/span&gt; en un código Java:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;public int Minima_devolucion(int cantidad_devuelta, int[]  monedas){&lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  //Creamos la matriz de devoluciones&lt;br /&gt;  int[][]  matriz_cambio = new int[monedas.length+1][cantidad_devuelta+1];&lt;br /&gt;  &lt;br /&gt; //Rellenamos la 1ª columna de ceros&lt;br /&gt; for(int i = 0; i &lt; monedas.length; i++)&lt;br /&gt;     matriz_cambio[i][0] = 0;&lt;br /&gt;  &lt;br /&gt; //La 1ª fila menos la 1ª columna un número alto&lt;br /&gt; for(int j = 1; j &lt;= cantidad_devuelta; j++)&lt;br /&gt;     matriz_cambio[0][j] = 999999;&lt;br /&gt;  &lt;br /&gt; for(int i = 1; i &lt;= monedas.length ; i++)&lt;br /&gt;    for(int j = 1; j &lt;= cantidad_devuelta; j++){&lt;br /&gt;     if(monedas[i-1] &gt; j ){&lt;br /&gt;       //Si la moneda es superior a la cantidad a devolver&lt;br /&gt;       matriz_cambio[i][j] = matriz_cambio[i-1][j]; &lt;br /&gt;     }else{&lt;br /&gt;       //Si la moneda no es superior a la cantidad a devolver&lt;br /&gt;     &lt;br /&gt;       //Calcular cual es el mínimo de estas dos posiciones&lt;br /&gt;       int minimo = 0; //Guardaremos aquí el mínimo&lt;br /&gt;     &lt;br /&gt;      if(matriz_cambio[i-1][j] &lt; matriz_cambio[i][j - monedas[i-1]] + 1){&lt;br /&gt;        minimo = matriz_cambio[i-1][j];&lt;br /&gt;      }else{&lt;br /&gt;        minimo = matriz_cambio[i][j - monedas[i-1]] + 1;&lt;br /&gt;      }&lt;br /&gt;      //Guardamos mínimo&lt;br /&gt;      matriz_cambio[i][j] = minimo;&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt; return matriz_cambio[monedas.length][cantidad_devuelta];&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-8268670659864651739?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/8268670659864651739/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/05/problema-de-las-monedas-con.html#comment-form' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/8268670659864651739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/8268670659864651739'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/05/problema-de-las-monedas-con.html' title='Problema de las monedas con programación dinámica'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-4910618848134765361</id><published>2009-04-30T15:18:00.000-07:00</published><updated>2009-04-30T15:30:31.335-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Problemas de programación dinámica'/><title type='text'>Características de un Problema de Programación Dinámica</title><content type='html'>&lt;div style="text-align: justify;"&gt;Para que un &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;problema&lt;/span&gt; pueda ser resuelto con la técnica de &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;programación dinámica&lt;/span&gt;, debe&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;cumplir con ciertas características:&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Naturaleza secuencial de las decisiones: El &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;problema&lt;/span&gt; puede ser dividido en etapas.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Cada etapa tiene un numero de estados asociados a ella.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;La decisión óptima de cada etapa depende solo del estado actual y no de las decisiones&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;anteriores.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;La decisión tomada en una etapa determina cual será el estado de la etapa siguiente.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;En síntesis, la política óptima desde un estado s de la etapa k a la etapa final esta constituida&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;por una decisión que transforma s en un estado s0 de la etapa k +1 y por la política óptima&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;desde el estado s0 hasta la etapa final.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-4910618848134765361?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/4910618848134765361/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/04/caracteristicas-de-un-problema-de.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/4910618848134765361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/4910618848134765361'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/04/caracteristicas-de-un-problema-de.html' title='Características de un Problema de Programación Dinámica'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6032501312965262597.post-1803743116775528192</id><published>2009-04-23T09:13:00.001-07:00</published><updated>2009-05-07T03:15:53.474-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Definición de programación dinámica'/><title type='text'>La programación dinámica</title><content type='html'>La &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;pr&lt;/span&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;ogramación dinámic&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;a&lt;/span&gt; es utilizada en compiladores, consiste en solucionar cierto problema diviendolo en subproblemas más sencillos, calculando sus resultados y almacenándolos. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Estos resultados posteriormente se utilizan para la resolución del problema final.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Almacenar resultados de subproblemas es una gran ventaja en cálculos dónde se repiten las mismas operación múltiples veces, mediante el método de &lt;span style="font-weight: bold;"&gt;la programación dinámica&lt;/span&gt; estas operaciones sólo se realizan una vez y se guarda la solución.&lt;br /&gt;&lt;br /&gt;Se dice de la programación dinámica que es un método para resolver problemas que exhiben propiedades de &lt;a href="http://webysw.blogspot.com/2009/05/subestructura-optima-y-subproblemas.html" title="problemas sobrepuestos y  estructura óptima" alt="problemas sobrepuestos y  estructura óptima"&gt;problemas sobrepuestos y  estructura óptima&lt;/a&gt;.&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6032501312965262597-1803743116775528192?l=webysw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://webysw.blogspot.com/feeds/1803743116775528192/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://webysw.blogspot.com/2009/04/la-programacion-dinamica.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/1803743116775528192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6032501312965262597/posts/default/1803743116775528192'/><link rel='alternate' type='text/html' href='http://webysw.blogspot.com/2009/04/la-programacion-dinamica.html' title='La programación dinámica'/><author><name>Adrián Manso</name><uri>http://www.blogger.com/profile/08773756272988912471</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
