22 Marzo 2022 💈
Programación dinámica
- Tenemos un array donde guardamos resultados intermedios para calcular el resultado final.
- Es un método iterativo, cuyo origen es una función recursiva. Sustituimos las llamadas recursiva por accesos a las posiciones del array.
- Se repiten operaciones, por tanto se guardan las calculadas en un array para no recalcularlas varias veces.
Problema del cambio
Lo que no se ve son 10 céntimos :-)
- Buscar el mínimo para no pasarse, usando la moneda de la iteración o de iteraciones anteriores.
Backtracking
- Problema de las 8 reinas: colocar 8 reinas en un tablero sin que se coman.
- Backtracking explora el grafo, va desarrollando estados hasta que encuentra una solución. Es un algoritmo de fuerza bruta, puesto que lo que hace es desarrollar estados de forma rápida hasta encontrar una solución.
- Técnica ineficiente, con complejidades exponenciales.
- Grafo implícito: grafo que se desarrolla a medida que se va recorriendo. Ahorra tiempo de ejecución y espacio en memoria.
Esquema Backtracking
public static void backtracking(Estado e) {
if (e.esSolucion()) { System.out.println(e); haySolucion= true;
}
else {
Estado estadoHijo= null;
while(e.hasNextHijos() && !haySolucion) {
// siguiente estado hijo válido
estadoHijo= e.nextHijo();
if (estadoHijo!=null) // puede que no queden hijos válidos backtracking(estadoHijo);
}
} }
29 Marzo 2022 🗿
- Backtracking busca todas las soluciones posibles.
- También se puede buscar la solución óptima.
Poda de nodos
- Consiste en establecer una condición que impida seguir desarrollando nodos aunque sean válidos.
- Se aplica cuando tenemos que buscar una solución óptima.
- Backtracking tiene complejidad explonencial.
Ejercicio formar palabras a partir de un conjunto de letras
public static void backtracking (int nivel) {
if (nivel==m) //hay ya una palabra completa {
mostrarSolucion();
cont++;
}
else {
for (int i=0;i<n;i++){
if (!marca[i]) {
sol[nivel] =vLetras[i];
marca[i]=true;
backtracking(nivel+1);
marca[i]=false;
}
}
}
}
Problema de la asignación de tareas a agentes
static void backtracking (int nivel) {
if (nivel==n) { //hay ya una asignación completa
if (coste<costeMejor) {
for (int k=0;k<n;k++){
asigMejor[k]=asig[k];
costeMejor=coste;
}
} }
else {
for (int i=0;i<n;i++){
if (!marca[i] && coste<costeMejor ) //ostemMejor->poda
asig[nivel]=i;
coste=coste+w[nivel][i];
marca[i]=true;
backtracking(nivel+1);
coste=coste-w[nivel][i];
marca[i]=false;
}
}
}
- Se podría hacer una poda (costemejor).
5 Abril 2022 🔵
- Aplicamos la poda en los problemas de optimización.
Problema del salto del caballo
static void backtracking (int salto,int x,int y) {
if (salto==n*n+1) { // ya acabó de recorrer tablero
seEncontro=true;
mostrarSolucion(); }
else
for (int k=0;k<=7;k++) {
int u=x+h[k]; // nueva posición
int v=y+v[k];
if (!seEncontro &&
u>=0 && u<=n-1 && v>=0 && v<=n-1 && // dentro tablero
tab[u][v]==0) { // casilla no utilizada
tab[u][v]=salto;
backtracking (salto+1,u,v);
tab[u][v]=0;
}
} }
Tema 7, Ramificación y poda 🔊
- No hace falta tener una asignación secuencial.
- Backtracking es recursivo, mientras que poda es iterativo.
public void realizarAnchura(Estado e) {
Cola cola= new Cola(); // Cola FIFO (1o en entrar --> 1o en salir)
boolean haySolucion= false; // Para buscar la primera solución Estado actual;
Estado actual;
cola.insertar(e); // mete estado e en la cola
while (!cola.esVacia() && !haySolucion) {
actual= cola.extraer();
// Examinar todos los hijos del estado actual
for (Estado estadoHijo : actual.expandir()) {
if (estadoHijo.esSolucion())
haySolucion= true;
else
cola.insertar(estadoHijo);
}
} }
Diferencias de poda con backtracking:
- Desarrollo de los nodos en anchura.
- Aplicamos heuristico para seleccionar cuál de ellos vamos a desarrollar.
MALA FORMA, sirve para hallar una solución. Para hallar la solución óptima es malo.
19 Abril 2022 ⏰
- El heurístico de ramificación permite saber los nodos que llevan a la solución final
- El heurístico de poda permite ir eliminando aquellos nodos que superen la cota.