Dpto. O.E.I. – U.P.M. ALGORÍTMICA 14/ENE/11 1º) (3’5 Puntos) Se dispone de un tablero de 6×6 y seis conjuntos de seis fichas de distintos colores. Se pide: Desarrollar un algoritmo en Pascal que sitúe las fichas en el tablero con las siguientes restricciones: No pueden aparecer dos fichas del mismo color en la misma fila, ni en la misma columna No puede haber dos fichas del mismo color en ninguna casilla de las dos diagonales principales No puede haber dos fichas del mismo color en las cuatro casillas centrales del tablero. En la figura aparece una posible solución al problema (representando los seis colores de las fichas por los valores entre 0 y 5) CONST N = 6; Vacio = 0; TYPE tTablero = ARRAY[1..N, 1..N] OF 0..N; 0 1 4 3 5 2 1 2 3 0 4 5 2 0 5 1 3 4 3 5 0 4 2 1 4 3 2 5 1 0 5 4 1 2 0 3 VAR Tablero: tTablero; I, J: Integer; Solucion: Boolean; PROCEDURE escribir(Tablero: tTablero); VAR I, J: Integer; BEGIN FOR I := 1 TO N DO BEGIN FOR J := 1 TO N DO Write(Tablero[I, J]:2); WriteLn; END END; FUNCTION Aceptable(Tablero: tTablero; Fila, Columna, Color: Integer): Boolean; VAR I: Integer; Correcto : Boolean; BEGIN Correcto := true; I := 1; WHILE (I <= N) AND Correcto DO BEGIN Correcto := (Tablero[Fila, I] <> Color) AND (Tablero[I, Columna] <> Color) AND NOT ((Tablero[I, I] = Color) AND (Fila = Columna)) AND NOT ((Tablero[I, N - I + 1] = Color) AND (Fila + Columna = (N + 1))); I := I + 1 END; Aceptable := Correcto END; PROCEDURE Ensayar(VAR Tablero: tTablero; Fila, Columna: Integer; VAR Solucion: Boolean); VAR Color: 0..N; BEGIN Columna := Columna + 1; IF Columna = (N + 1) THEN BEGIN Fila := Fila + 1; Columna := 1 END; Color := 0; REPEAT Color := Color + 1; IF Aceptable(Tablero, Fila, Columna, Color) THEN BEGIN Tablero[Fila, Columna] := Color; IF (Fila = N) AND (Columna = N) THEN Solucion := TRUE ELSE BEGIN Ensayar(Tablero, Fila, Columna, Solucion); IF NOT Solucion THEN Tablero[Fila, Columna] := Vacio; END END UNTIL Solucion OR (Color = N); END; BEGIN FOR I := 1 TO N DO FOR J := 1 TO N DO Tablero[I, J] := Vacio; Solucion := FALSE; Ensayar(Tablero, 1, 0, Solucion); IF Solucion THEN escribir(Tablero) ELSE WriteLn('No existe solucion'); END. Universidad Politécnica de Madrid – E.U. Informática Página 1 2º) (3’5 Puntos) Se posee un mapa de carreteras que contiene 15 ciudades, y se pretende planificar un viaje desde una ciudad de origen a una ciudad de destino. Dicho viaje deberá incluir obligatoriamente la visita a tres ciudades intermedias previamente determinadas y nunca se visitará una ciudad en más de una ocasión. Se sabe que el mapa es conexo. Se pide: desarrollar un algoritmo en Pascal que muestre el camino más corto entre la ciudad origen y la ciudad destino y que incluya las tres ciudades intermedias (en cualquier orden). Para resolver el problema se dispondrá de una matriz de costes con las conexiones por carretera entre las 15 ciudades. Las ciudades que no estén conectadas tendrán asignado el valor infinito en la posición correspondiente de la matriz. Las ciudades intermedias vendrán marcadas en un vector de booleanos. CONST N = 15; { Número de vértices del grafo } INFINITO = MaxInt; NO_VISITADO = -1; TYPE tCamino = ARRAY [1..N] OF Integer; { vector para almacenar caminos simples } tVisitados = ARRAY [1..N] OF Boolean; tMatrizCoste = ARRAY [1..N, 1..N] OF Integer; FUNCTION RutaCompletada(Camino: tCamino; Intermedias: tVisitados; Origen, Destino: Integer): Boolean; VAR estaCompleta: Boolean; v: Integer; BEGIN estaCompleta := (Camino[Origen] <> NO_VISITADO) AND (Camino[Destino] <> NO_VISITADO); FOR v := 1 TO N DO IF Intermedias[v] THEN estaCompleta := estaCompleta AND (Camino[v] <> NO_VISITADO); RutaCompletada := estaCompleta END; PROCEDURE ImprimirCamino(Camino: tCamino; vOrigen, vActual: Integer); BEGIN IF Camino[vActual] = vOrigen THEN Write(vOrigen:2, ', ', vActual:2) ELSE BEGIN ImprimirCamino(Camino, vOrigen, Camino[vActual]); Write(', ', vActual:2) END END; { P R O G R A M A P R I N C I P A L } FOR v := 1 TO N DO BEGIN Intermedias[v] := false; Visitados[v] := false; caminoActual[v] := NO_VISITADO; caminoOptimo[v] := NO_VISITADO; END; { EJEMPLO: ciudades intermedias 5, 3 y 2 } Intermedias[5] := true; Intermedias[3] := true; Intermedias[2] := true; cActual := 0; cOptimo := INFINITO; origen := 1; destino := N; caminoActual[origen] := origen; PlanificarRuta(GNV, Intermedias, origen, origen, destino, cActual, cOptimo, caminoActual, caminoOptimo); IF cOptimo <> INFINITO THEN BEGIN ImprimirCamino(caminoOptimo, origen, destino); WriteLn(' Coste = ', cOptimo); END ELSE WriteLn('El problema no tiene solución') Universidad Politécnica de Madrid – E.U. Informática Página 2 PROCEDURE PlanificarRuta(GNV: tMatrizCoste; Intermedias: tVisitados; origen, actual, destino: Integer; costeActual: Integer; VAR costeOptimo: Integer; VAR caminoActual, caminoOptimo: tCamino); VAR v: Integer; BEGIN FOR v:= 1 TO N DO IF (caminoActual[v] = NO_VISITADO) AND (GNV[actual, v] <> INFINITO) THEN BEGIN { anotar } caminoActual[v] := actual; costeActual := costeActual + GNV[actual, v]; { ¿es solución? } IF (v = destino) AND RutaCompletada(caminoActual, intermedias, origen, destino) THEN BEGIN IF costeActual < costeOptimo THEN BEGIN { copiar solución óptima } costeOptimo := costeActual; caminoOptimo := caminoActual; END END ELSE { si el candidato coincide con el destino, no encontraremos solución } IF (costeActual < costeOptimo) AND (v <> destino) THEN PlanificarRuta(GNV, Intermedias, origen, v, destino, costeActual, costeOptimo, caminoActual, caminoOptimo); { desanotar } caminoActual[v] := NO_VISITADO; costeActual := costeActual - GNV[actual, v]; END END; Universidad Politécnica de Madrid – E.U. Informática Página 3 3º) (3 Puntos) Dado un Grafo Árbol Dirigido (no valorado) del que se conoce el nodo raíz y representado por listas de adyacencia, se pide: siguiendo el esquema Divide y Vencerás, desarrollar en lenguaje Pascal un algoritmo que determine la altura del árbol. CONST N = 20; TYPE pNodo = ^tNodo; tNodo = RECORD Vertice: Integer; Sig: pNodo; END; tListasAdy = ARRAY [1..N] OF pNodo; tAlturas = ARRAY [1..N] OF Integer; FUNCTION Maximo(V: tAlturas; Iz, De: Integer): Integer; VAR Medio, m1, m2: Integer; BEGIN IF Iz = De THEN Maximo := V[Iz] ELSE BEGIN Medio := (Iz + De) DIV 2; m1 := Maximo(V, Iz, Medio); m2 := Maximo(V, Medio + 1, De); IF m1 > m2 THEN Maximo := m1 ELSE Maximo := m2 END END; { Maximo } FUNCTION AlturaArbol(VAR G: tListasAdy; vActual: Integer): Integer; VAR v, h, numDescendientes: Integer; altura: tAlturas; Aux: pNodo; BEGIN IF G[vActual] = NIL THEN h := 1 ELSE BEGIN numDescendientes := 0; Aux := G[vActual]; WHILE Aux <> NIL DO BEGIN numDescendientes := numDescendientes + 1; altura[numDescendientes] := AlturaArbol(G, Aux^.Vertice); Aux := Aux^.Sig; END; { Combinar soluciones } h := 1 + Maximo(altura, 1, numDescendientes); END; AlturaArbol := h; END; { AlturaArbol } { P R O G R A M A P R I N C I P A L } WriteLn('Altura del Árbol: ', AlturaArbol(G, Raiz)); Universidad Politécnica de Madrid – E.U. Informática Página 4