Programación Dinámica (iii) optimizar el camino de la violencia recursiva - Matriz digital y el camino mínimo

título

Matriz m, se inicia desde la parte superior izquierda o derecha sólo puede ir hacia abajo, y finalmente llega a la posición de la esquina inferior derecha, los caminos de todos los números se suman y es el camino, todos los caminos vía de retorno y el mínimo.

por ejemplo

Dada m como sigue:

1 3 5 9
8 1 3 4
5 0 6 1
8 8 4 0

1,3,1,0,6,1,0 camino es el más pequeño de todos los caminos y senderos, la regresaron 12

pensamiento

  1. Considere subestructura óptima, que puede dividirse en sub-problemas. Desde el comienzo de la matriz ápice, encontrar el camino más corto y, ya que sólo el abajo o hacia la derecha, se puede considerar de dos nueva situación, ese punto de vista y el punto justo por debajo del vértice de dos nueva matriz, acaba de encontrar tanto la matriz de trayectoria mínima y luego descubrir que el más pequeño, más el valor del vértice actual es la trayectoria mínima en toda la matriz y.
  2. Después de que la solución recursiva escrito, se dará cuenta de la superposición de sub-problemas, es adecuado para la acción reguladora para resolver el problema, ya que el uso excesivo de memoria tipo recursividad.
  3. análisis de la dependencia de la memoria de datos se puede definir en el orden calculado, el primer valor calculado dependiente requiere poco a poco para obtener el valor final.

la violencia recurrente

Pseudocódigo

minSum(int[][] arr, int x, int y)
    return arr[x][y] + Math.min(minSum(arr,x+1,y),minSum(arr,x,y+1));

La idea es muy simple, la solución de todo el problema es aumentar el valor de la posición actual de distancia formar el camino de la derecha y bajar el menor de.
x e y seguirá aumentando, llega a la última línea de la frontera es xoy llega a la última, así que el código se vuelve a escribir como:

minSum(int[][] arr, int x, int y)
    int sum=0;
    if(x==arr.length-1)//到达右下角只有一条路可走
        for i=y...arr.length-1
            sum+=arr[x][i]
        return sum;
    if(y==arr.length-1)//到达右下角只有一条路可走
        for i=x...arr.length-1
            sum+=arr[i][y]
        return sum;
    return arr[x][y] + Math.min(minSum(arr,x+1,y),minSum(arr,x,y+1));

implementación de Java

public class 数字矩阵的最小路径和 {
  public static int minSum(int[][] arr, int x, int y) {
    int sum = 0;
    if (x == arr.length - 1) {//到达右下角只有一条路可走
      for (int i = y; i < arr[0].length; i++) {
        sum += arr[x][i];
      }
      return sum;
    }
    if (y == arr[0].length - 1) {//到达右下角只有一条路可走
      for (int i = x; i < arr.length; i++) {
        sum += arr[i][y];
      }
      return sum;
    }
    return arr[x][y] + Math.min(minSum(arr, x + 1, y), minSum(arr, x, y + 1));
  }

  public static void main(String[] args) {
    System.out.println(minSum(new int[][]{
        {1, 3, 5, 9},
        {8, 1, 3, 4},
        {5, 0, 6, 1},
        {8, 8, 4, 0},
    },0,0));
  }
}

Tipo de búsqueda de memoria

De acuerdo con las ideas anteriores presentados, los cambios en los parámetros investigados función recursiva, se puede utilizar una matriz bidimensional de los valores calculados de caché es muy simple, casi sin pensar puede ser reescrito después de las rutinas de maestros:

  public static int minSumMemory(int[][] arr, int x, int y, int[][] map) {
    int sum = 0;
    if (x == arr.length - 1) {//到达右下角只有一条路可走
      for (int i = y; i < arr[0].length; i++) {
        sum += arr[x][i];
      }
      map[x][y] = sum; // 缓存
      return sum;
    }
    if (y == arr[0].length - 1) {//到达右下角只有一条路可走
      for (int i = x; i < arr.length; i++) {
        sum += arr[i][y];
      }
      map[x][y] = sum;//缓存
      return sum;
    }
    //=====判断缓存,没有值再递归,保证一个xy组合只计算一次=====
    int v1 = map[x + 1][y];
    if (v1 == 0)
      v1 = minSum(arr, x + 1, y);
    int v2 = map[x][y + 1];
    if (v2 == 0)
      v2 = minSum(arr, x, y + 1);

    sum = arr[x][y] + Math.min(v1, v2);
    map[x][y] = sum; // 缓存
    return sum;
  }

En la violencia exponencial recursivo en general, el tipo de memoria es polinomial recursiva (de dos dimensiones de la matriz es de grado cuadrado) de nivel y vuelva a grabar la programación dinámica puede no ser capaz de mejorar la eficiencia, sino porque no hay uso recursividad, puede reducir el riesgo de desbordamiento de pila .

Programación dinámica

Antes se propone rutina para estudiar el proceso de obtener el valor de caché, el valor actual que se almacena en caché recursiva depende de qué valor, el proceso inverso es más dinámico de planificación.

En este ejemplo, la tabla de caché es una matriz de dos dimensiones, que finalmente tiene que rellenar todos los valores de punto, que es el camino mínimo para alcanzar este punto y la esquina inferior derecha. , La acción de abajo hacia arriba Recursive de arriba hacia abajo puede ser regulada, de la x, y empezar límite, es decir, la fila inferior y de la columna más a la derecha se inicia, ya que estos puntos a una sola ruta de acceso a la esquina inferior derecha, puede ser resuelto de forma natural.

            14
            5
            1
20  12  4   0

Luego llene la mitad del valor de su propia es muy simple + = por debajo ya la derecha de los pequeños números, el cálculo final de la posición 0-0, es decir, la respuesta final:

12  11  13  14
16  8   8   5
12  7   7   1
20  12  4   0

Echemos un vistazo al código:

  public static int dp1(int[][] arr) {
    final int rows = arr.length;
    final int cols = arr[0].length;
    int[][] dp = new int[rows][cols];
    dp[rows - 1][cols - 1] = arr[rows - 1][cols - 1];
    //打表:最右一列
    for (int i = rows - 2; i >= 0; i--) {
      dp[i][cols - 1] = arr[i][cols - 1] + dp[i + 1][cols - 1];
    }
    //打表:最后一行
    for (int i = cols - 2; i >= 0; i--) {
      dp[rows - 1][i] = arr[rows - 1][i] + dp[rows - 1][i + 1];
    }
    for (int i = rows - 2; i >= 0; i--) {
      for (int j = cols - 2; j >= 0; j--) {
        dp[i][j] = arr[i][j]+Math.min(dp[i+1][j],dp[i][j+1]);
      }
    }
    return dp[0][0];
  }

Dp tabla de dos dimensiones, la trayectoria mínima puede ser restaurada:

Escribir imágenes describen aquí

Este proceso es encontrar el orden más pequeño de la parte superior izquierda a la esquina inferior derecha, sobre la ruta de la matriz original para encontrar el número que corresponde muy bien.

método de compresión espacio: sólo matrices unidimensionales dp

La presente realización simplemente ruta de acceso y el valor mínimo, la ruta de salida requerida, el proceso intermedio sin reserva de regreso. Considere una matriz unidimensional para almacenar los valores recursivas, calculados para cada fila cubierta en la línea, que tiene un valor de 0-0 en una cifra final en él.

Para la presente realización, dado que el mismo número de filas y columnas, en la que es el tamaño de la matriz es posible, si no, se puede elegir el número de filas o columnas como el tamaño de la matriz, por supuesto, cambiará en consecuencia de propulsión, en filas modo (número de filas más) para promover o columna-Wise (más columnas) para avanzar.

Vamos a ilustrar este proceso:

  1. dp=new int[4];Los valores iniciales son todos 0
  2. Los datos de origen para ser actualizados [20 12 4 0], esta vez dp [i] representa una matriz de la (última fila, i) y el extremo trayectoria mínima;
  3. Iniciar actualización Ahora vamos dp [I] desde el más pequeño representante de la matriz de canal (la línea penúltima, i) y el punto final, para actualizar el último elemento, dp[3]=arr[倒数2行][最后一列]+dp[3];en este momento se convierte en dp [20 12 4 1]; actualización dp [2]: dp[2] = arr[倒数第二行][倒数第二列]+min(4,1)., 4 está por debajo del valor 1 es el valor correcto, por lo que puede lograr gradualmente la actualización
  4. Repita el paso 3 hasta que el procesamiento de la primera fila, devoluciones dp [0] para

código:

  /**
   * 空间压缩优化
   * @param arr
   * @return
   */
  public static int dp2(int[][] arr) {
    final int rows = arr.length;
    final int cols = arr[0].length;
    int N = 0;
    if (rows>=cols){
      N = cols;
    }
    int[] dp = new int[N];
    dp[N-1] = arr[rows - 1][N - 1];
    //打表:第一次更新
    for (int i = N - 2; i >= 0; i--) {
      dp[i] = arr[rows-1][i] + dp[i + 1];
    }
    // 行
    for (int i = rows-2; i >=0 ; i--) {
      dp[N-1]=arr[i][N-1]+dp[N-1];
      for (int j = N - 2; j >= 0; j--) {
        dp[j] = arr[i][j] + Math.min(dp[j],dp[j + 1]);
      }
      // Util.print(dp);
    }
    return dp[0];
  }

resumen

Este ejemplo de rutinas de optimización se puede aplicar a casi todas las necesidades de título de la tabla de programación dinámica de dos dimensiones por medio de un vuelco gama sin duda ahorra mucho espacio.

Pero el método de compresión espacio tiene limitaciones, la ruta específica que no puede ser deshecha solución óptima.

Los libros de referencia "Guía Código del programador entrevista."

Publicados 127 artículos originales · ganaron 97 Like · vistas 310 000 +

Supongo que te gusta

Origin blog.csdn.net/zhengwei223/article/details/78763904
Recomendado
Clasificación