Programación Lógica
Transcripción
Programación Lógica
Programación Lógica Hoja de problemas 3 1. Escribir los siguientes predicados: a) max(L,Max)::= calcula en Max el máximo de los elementos de la lista de enteros L b) minMax(L,Min,Max)::= calcula en Max el máximo y en Min el mı́nimo de los elementos de la lista de enteros L (en un sólo recorrido de la lista L). c) cuadrados(L,Lc)::= calcula en Lc la lista de los cuadrados de los enteros de la lista L. d) cuadrados2(L,Lc): análogo al anterior pero además asocia (con el functor ’:’) a cada elemento un entero indicando la posición de la lista donde aparece. Por ejemplo, para la lista L = [2, 3, 5, 1, 6] devolverá Lc = [1 : 4, 2 : 9, 3 : 25, 4 : 1, 5 : 36]. e) filtraPares(L,Lf )::= devuelve en la lista Lf los elementos pares que aparecen en la lista de enteros L f) eliminaDuplicados(L,L1)::= devuelve en L1 el resultado de eliminar los elementos duplicados de la lista L 2. Supongamos un grafo definido como (análogamente a lo visto en clase): arco(a,b). arco(a,e). arco(b,c). arco(b,f). arco(d,a). arco(e,d). arco(e,f). arco(f,c). arco(g,d). arco(g,h). arco(h,f). Nótese que este grafo contiene ciclos, por lo que no es correcto definir el predicado camino como: camino(X,X). camino(X,Y):- arco(X,Z), camino(Z,Y). ¿Qué ocurrirı́a con el objetivo camino(a,b)? Se pide: a) Hacer una definición correcta del predicado camino para grafos (posiblemente) cı́clicos como el del ejemplo (la idea es guardar los nodos visitados para impedir los recorridos cı́clicos). b) Desarrollar el árbol de búsqueda para el objetivo camino(g,c). c) ¿Como se podrı́a determinar si hay un camino entre g y c que no pase por f utilizando el programa anterior? d) Extender la definción de camino para que, en el caso de que haya camino entre dos nodos dados, devuelva además una lista con los nodos que forman dicho camino. 3. Escribir un predicado bin(N,L) que dado el entero (positivo) N , calcule en la lista L la representación binaria de dicho número. Hacer la conversión inversa (de binario a decimal). 4. La forma más directa de representar una matriz de dimension N ×M en prolog es mediante una lista (de longitud N ) de listas (de longitud M ). Ası́ por ejemplo, la matriz: 1 2 3 4 5 6 7 8 9 se representarı́a como [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]. Escribir un predicado que calcule la traspuesta de una matriz dada. 5. Consideremos los árboles binarios de búsqueda representados como vacio (árbol vacı́o) y arbol(HijoIzq,Raiz,HijoDer) y el predicado de inserción de un elemento visto en clase. Se pide: a) Escribir un predicado cons(L,A) que tome como entrada una lista de enteros L y construya el árbol A resultante de insertar cada uno de los elementos de dicha lista en un árbol vacı́o. Por ejemplo, el objetivo cons([6,3,4,2,8,1],A) debe producir A = arbol(arbol(arbol(arbol(vacio, 1, vacio), 2, vacio), 3, arbol(vacio, 4, vacio)), 6, arbol(vacio, 8, vacio)) b) Prolog proporciona un amplio repertorio de predicados de entrada/salida. En este ejercicio nos interesa el predicado write(T) que escribe en pantalla el término T , tab(N) que escribe en pantalla N espacios en blanco y el predicado nl que escribe un salto de lı́nea. Se pide programar un predicado escribe(A) que muestre en pantalla el árbol A en un formato “legible”. Por ejemplo, el del apartado anterior se quedarı́a como: 8 6 4 3 2 1 La idea es rotar el árbol de modo que la raiz quede a la izquierda y escribir el hijo derecho por encima y el izquierdo por debajo. Además cada nodo se indenta horizontalmente dependiendo de la profundidad que tenga en el árbol. 6. Una lista puede empaquetarse mediante otra lista de pares elemento/multiplicidad de modo que la multiplicidad indica el número de apariciones consecutivas del elemento. Ası́ por ejemlo, la lista [a, a, a, b, b, a, a, c, c, c, c] queda empaquetada como [a : 3, b : 2, a : 2, c : 4]. Se piden dos predicados: empaqueta(+L,-Le)::= devuelve en Le el empaquetado correspondiente a la lista de entrada L. desempaqueta(+Le,-L)::= realiza la operación inversa con la lista empaquetada Le. 7. Supongamos que codificamos el stock de una tienda de software mediante una lista de elementos de la forma articulo(identificador, cantidad). Por ejemplo, la lista [articulo(windowsXP,0), articulo(ubuntu,114), articulo(explorer,0),articulo(swiprolog, 37), articulo(windowsXP,0), articulo(ubuntu,6)] indicarı́a que disponemos de un stock con 0 cd’s de windows XP, 114 cd’s de ubuntu, 0 cd’s de internet explorer, 37 cd’s de swi prolog, 0 cd’s de windowsXP y 6 cd’s de ubuntu. A la vista de este ejemplo, se aprecia que esta representación puede compactarse sumando las cantidades de los artı́culos disponibles y eliminando aquellos cuya cantidad (acumulada) es 0. En nuestro ejemplo, al compactar obtendrı́amos [articulo(ubuntu,120),articulo(swiprolog,37)]. Implementar un predicado para compactar stocks. 8. Los multiconjuntos (conjuntos que admiten repetición de elementos) pueden representarse en Prolog como una lista de la forma [. . . , E : N, . . .] donde E es el elemento y N el número de veces que aparece. Ası́ el multiconjunto { {1, 2, 3, 4, 3, 3, 4, 4, 3, 3, 5, 6, 7, 8, 7, 6, 5, 4} } se representa como [1 : 1, 2 : 1, 3 : 5, 4 : 4, 5 : 2, 6 : 2, 7 : 2, 8 : 1]. Se pide: a) Escribir un predicado añade para insertar un elemento en un multiconjunto. b) Escribir un predicado que convierta una lista dada (posiblemente con elementos repetidos) en un multiconjunto. c) Escribir un predicado que devuelva la multiplicidad (número de apariciones) de un elemento en un multiconjunto . 9. Implementar un programa Prolog para obtener soluciones al problema de colocar (todas) las fichas del dominó en secuencia de modo que casen dos a dos (en la terminologı́a habitual del dominó). 10. Las expresiones aritméticas se pueden escribir en notación postfija sin necesidad de paréntisis ni ningún otro tipo de delimitador. Por ejemplo, la expresión (3 + 4) ∗ ((6 − 2)/1), en notación postfija es 3 4 + 6 2 − 1 / ∗. La evaluación de este tipo de expresiones puede hacerse fácilmente utilizando una pila. La expresión se procesa de izquierda a derecha: cada vez que se encuentra un operando se apila, cuando se encuentra un operador se aplica a los dos primeros operandos de la pila (la cima y el siguiente) y el resultado se apila nuevamente. Si la expresión es correcta, al final del proceso se habrá consumido toda la expresión y la pila contendrá un único elemento con el resultado de la evaluación. Se pide implementar un predicado eval(L,V) que tome como input una lista de operadores/operandos que representan la expresión postfija y devuelva el valor de su evaluación. Por ejemplo, para la expresión anterior eval([3,4,+,6,2,-,1,/,*],V). deberı́a dar la respuesta V = 28.