Intervalo DP | 1: problemas de la cadena de la matriz (incluyendo la optimización) - Ejemplo: Matriz de cadena combinada piedras

Matrix problema de multiplicación de la cadena:  cadena de matriz de n Dada <A1, A2, A3, ... , An>, el tamaño de la matriz de Ai  p_ {i-1} \ cdot p_ {i} (0 \ leq i \ leq n) . esquema de soportes completa, por lo que calculan el producto A1A2 ... Un mínimo número de multiplicaciones escalares requerido.


directorio

En primer lugar, el análisis algoritmo

1, las características estructurales óptimas soportes Esquemas

2, un programa recursivo para resolver

En segundo lugar, el algoritmo

1, calcular el coste óptimo

Optimización del método write - complejidad del tiempo es O (n ^ 3)

El método optimizado - complejidad del tiempo cae O (n ^ 2)

2, la solución óptima constructo

En tercer lugar, ejemplos

1, la cadena de matriz problema de multiplicación

Completa Código 1 AC :( sin optimizar el tiempo la complejidad  )O (n ^ 3) 

código de autenticación completa 2 :( optimización de la complejidad del tiempo  O (n ^ 2) 

2. piedras consolidados

Completa Código 1 AC :( sin optimizar el tiempo la complejidad )O (n ^ 3) 

código de autenticación completa 2 :( optimización de la complejidad del tiempo  O (n ^ 2) 

fin 



Cuando sólo dos matrices A y B son compatibles, es decir, el número de columnas igual al número de filas A, B, puede multiplicado. Si A es una q p × matriz, B es q r × matriz, entonces el producto C es p matriz r ×. C se calcularon en PQR multiplicaciones. Nosotros empleamos un número de veces que la multiplicación para representar el costo de la computación

Para obtener más matriz se multiplican continuamente el problema, llamamos a los problemas de la cadena de la matriz. La multiplicación de matrices es asociativa, por lo que cualquier método de paréntesis, no afecta el resultado de una pluralidad de multiplicación de matrices. Sin embargo, diferentes esquemas de paréntesis (cambiantes orden de cálculo) afectará el cálculo de costes de la cadena de multiplicación de matrices:


En primer lugar, el análisis algoritmo

1, las características estructurales óptimas soportes Esquemas

El primer paso en el método de programación dinámica es encontrar la subestructura óptima, a continuación, puede utilizar esta subestructura, la solución óptima del problema original de ser óptima destructor crear problemas.

(Por conveniencia, A_ {} i..j denotamos A_iA_ {i + 1} ... A_jla matriz resultado de la multiplicación)

  • De toda parcial de aspecto: una matriz para cada cadena  A_ {} i..j, si sus soportes de, que debe estar en una de dos matrices Anuncioy A_ {d + 1}dividida entre abierto, a continuación, vamos a discutir Ayuda}y A_ {d} + 1..jsoportes de.
  • A partir de entonces a todo el local de Sede: el cálculo A_ {} i..j de costos = calcular Ayuda}cálculo de costes +  A_ {d} + 1..j costo + calculado  A_ {i..d} \ cdot A_ {d} + 1..jcosto.

Por lo tanto, con el fin de construir una cadena matriz de  A_ {} i..n solución de problema de multiplicación óptima, se puede descomponer el problema en dos sub-problemas:  Ayuda} y  A_ {d} + 1..n optimización paréntesis problema. Después se obtiene la cuestión de la solución sub-óptima, entonces la solución sub-óptima al problema de combinar .


2, un programa recursivo para resolver

  • El tamaño de la matriz correspondiente a la almacenada unidimensional array p [0..n]  , la matriz de Ai tamaño es  p_ {i-1} \ cdot P_ {i}.
  • Calcular el coste de almacenamiento correspondiente en la matriz bidimensional American National Standard [1..n, 1..n]  , se utilizó ans [i, j] denota una matriz de  A_ {} i..j coste computacional mínima, el coste de calcular el mínimo del problema original en el ANS final de [ 1, n] en su interior. 
  • Optimal punto de división correspondiente a la almacenada array divide en dos dimensiones [1..n, 1..n]  , se utiliza la brecha [i, j] registra la ans coste óptimo [i, j] que corresponden a la óptima dividiendo punto d. (Esta matriz es útil al imprimir la estructura óptima)

De acuerdo con las características estructurales anteriormente descritas de la esquema óptimo de los soportes, podemos enumerar la ecuación de transición de estado:

  • Cuando i = j cuando: \ Bg_white ans [i, j] = 0
  • Cuando i <j cuando: años [i, j] = min_ {i \ leq k <j} (años [i, k] + años [k + 1, j] + p_ {i-1} p_kp_j)

ps: cuando se define la matriz de la American National Standard todo inicializado a cero.


En segundo lugar, el algoritmo

1, calcular el coste óptimo

Análisis Se conoce a partir del algoritmo, las necesidades de interrogación para abajo hacia arriba métodos: problema de optimización para manejar la cadena de sub-matrices, a continuación, tomados juntos.

Por eso, cuando nos dimos cuenta: Debe ser la longitud de la matriz de la cadena 2 comenzaron a discutir, y luego discutir la longitud de la matriz de cadena de 3 ... n la discusión final de la longitud de la matriz de la cadena, que consiste en obtener una respuesta sobre esta base. Con cierta extensión se ha determinado en la discusión, no se escapan al caso, o afecta al valor óptimo.


Optimización del método write - complejidad del tiempo es O (n ^ 3)

Entonces nuestra estructura de bucle debe tener este aspecto:

  • El primer bucle de capa: longitud l = 2..n
  • El segundo bucle de la capa: la discusión de cada longitud de matriz de cadena de l A_ {} i..j: i = 1..n - l 1, j = i + l + 1
  • El tercer bucle de la capa: la determinación de una óptima dividiendo punto k = i..j-1
/* 计算n元矩阵链p的最优代价
 * 动态规划的每一步结果储存在 ans与 divide中 */
void MatrixChainOrder(int p[], int n) {
    /* 矩阵链长度为2到n */
    for (int l = 2; l <= n; l++) {
        /* 讨论长度为l的矩阵链A[i..j] */
        for (int i = 1; i <= n - l + 1; i++) {
            int j = i + l - 1;
            ans[i][j] = INT_MAX;
            /* 依次讨论每一个分割点d:将矩阵链A[i..j]分成A[i..d]和 A[d+1..j] */
            for (int temp, d = i; d < j; d++) {
                temp = ans[i][d] + ans[d + 1][j] + p[i - 1] * p[d] * p[j];
                /* 记录下矩阵链A[i..j]最小的情况 */
                if (temp < ans[i][j]) {
                    ans[i][j] = temp;
                    divide[i][j] = d;
                }
            }
        }
    }
}

El método optimizado - complejidad del tiempo caeO (n ^ 2) 

Tres métodos básicos anteriores ciclo es inevitable, pero pueden reducir en gran medida el número de ciclos para atravesar una tercera capa, de tal manera que la complejidad de tiempo se reduce O (n ^ 2) . De acuerdo con la matriz de la cadena modelar las características del problema, su dinámica Solver puede utilizar la optimización de la desigualdad cuadrilátero . (Los enlaces son principio de optimización detallada, la complejidad de tiempo del proceso de certificación)

Así, los satisface el punto de decisión óptimas de la relación: brecha [i] [j-1] \ leq brecha [i] [j] \ leq brecha [i + 1] [j]así que tercer bucle capa puede optimizarse como sigue: En un determinado intervalo [ Divide [i] [j -1], Divide [hecho +1 i] [j] ] dentro de la poligonal, que margen de desplazamiento mucho menos que n.

PS: prestar atención a los casos límite, es necesario dividir la lista inicial.

/* 计算n元矩阵链p的最优代价
 * 动态规划的每一步结果储存在 ans与 divide中 */
void MatrixChainOrder(int p[], int n) {
    /* 初始化divide数组 */
    for (int i = 1; i <= n; i++)
        divide[i][i] = i;
    /* 矩阵链长度为2到n */
    for (int l = 2; l <= n; l++) {
        /* 讨论长度为l的矩阵链A[i..j] */
        for (int i = 1; i <= n - l + 1; i++) {
            int j = i + l - 1;
            ans[i][j] = INT_MAX;
            /* 在特定区间内:依次讨论每一个分割点d,将矩阵链A[i..j]分成A[i..d]和 A[d+1..j] */
            for (int temp, d = divide[i][j - 1]; d <= divide[i + 1][j]; d++) {
                temp = ans[i][d] + ans[d + 1][j] + p[i - 1] * p[d] * p[j];
                /* 记录下矩阵链A[i..j]最小的情况 */
                if (temp < ans[i][j]) {
                    ans[i][j] = temp;
                    divide[i][j] = d;
                }
            }
        }
    }
}

2, la solución óptima constructo

En el bidimensional array dividimos [i, j] ha sido registrada en  A_ {} i..j el punto de corte óptimo punto, ya que la óptima dividiendo matriz de cadena puede ser descompuesto en sub-óptima dividiendo cadena, por lo que podemos impreso de forma recursiva.

/* 根据divide数组,输出A[i..j]的最优情况 */
void PrintDivide(int i, int j) {
    if (i == j)
        printf("A%d", i);
    else {
        int d = divide[i][j];  //找到分界点
        printf("(");
        PrintDivide(i, d);
        PrintDivide(d + 1, j);
        printf(")");
    }
}

En tercer lugar, ejemplos

1, la cadena de matriz problema de multiplicación

logro 10 en Tiempo 2020 de marzo de 10 Martes, 7:55
descuento 0.8 Tiempo de descuento 2020 Martes, 7 de abril de 23:55
Permitir finales no La hora de cierre 2020 Martes, 7 de abril de 23:55

entrada:

Un total de dos líneas

La primera fila N (1 <= N <= 100), representativa del número de matrices.

La segunda fila tiene el número de N + 1, respectivamente, A1, A2 ...... An + 1 (1 <= Ak <= 2,000), Ak y Ak + 1 representa el k una matriz Ak X Ak + 1 en forma.

salida:

Un total de dos líneas

La primera línea de M, es el coste óptimo. Nota: el caso de prueba para asegurarse de que el valor de menos de 2 ^ 31 M

orden óptimo del segundo acto. Los (A1 ((A2A3) A4)), sino también los paréntesis más externos.

Nota: La prueba tiene que asegurarse de que la salida de la planta del pie, por lo que no existe una situación de AAA.

  entrada de prueba Resultados previstos plazo Límite de memoria proceso adicional
Caso de Prueba 1  
  1. 6↵
  2. 30 35 15 5 10 20 25↵
 
  1. 15125↵
  2. ((A1 (A2A3)) ((A4A5) A6)) ↵
1 segundo 64M

0

 


El método específico se ha explicado en detalle anteriormente, que ~

Principal Nota: Cuando el número de la matriz de cadena de la matriz a la salida de una entre paréntesis, o será un wa.

Código completa de CA 1: (sin optimizar O (n ^ 3)el tiempo de la complejidad)

//
// Created by LittleCat on 2020/3/10.
//

#include <cstdio>
#include <climits>

using namespace std;
#define MAX 2010

int ans[MAX][MAX] = {0}; // 保存矩阵链 A[i..j]的最小代价
int divide[MAX][MAX] = {0};   // 记录最小代价ans[i,j]对应的分割点

/* 计算n元矩阵链p的最优代价
 * 动态规划的每一步结果储存在 ans与 divide中 */
void MatrixChainOrder(int p[], int n) {
    /* 矩阵链长度为2到n */
    for (int l = 2; l <= n; l++) {
        /* 讨论长度为l的矩阵链A[i..j] */
        for (int i = 1; i <= n - l + 1; i++) {
            int j = i + l - 1;
            ans[i][j] = INT_MAX;
            /* 依次讨论每一个分割点d:将矩阵链A[i..j]分成A[i..d]和 A[d+1..j] */
            for (int temp, d = i; d < j; d++) {
                temp = ans[i][d] + ans[d + 1][j] + p[i - 1] * p[d] * p[j];
                /* 记录下矩阵链A[i..j]最小的情况 */
                if (temp < ans[i][j]) {
                    ans[i][j] = temp;
                    divide[i][j] = d;
                }
            }
        }
    }
}

/* 根据divide数组,输出A[i..j]的最优情况 */
void PrintDivide(int i, int j) {
    if (i == j)
        printf("A%d", i);
    else {
        int d = divide[i][j];  //找到分界点
        printf("(");
        PrintDivide(i, d);
        PrintDivide(d + 1, j);
        printf(")");
    }
}

int main() {
    int n;
    scanf("%d", &n);
    int p[MAX];
    for (int temp, i = 0; i <= n; i++)
        scanf("%d", &p[i]);

    MatrixChainOrder(p, n);
    printf("%d\n", ans[1][n]);
    if (n == 1)
        printf("(A1)");
    else
        PrintDivide(1, n);
    printf("\n");
}


Completa Código AC 2: (optimización de la O (n ^ 2)complejidad del tiempo) 

//
// Created by LittleCat on 2020/3/10.
//

#include <cstdio>
#include <climits>

using namespace std;
#define MAX 2010

int ans[MAX][MAX] = {0}; // 保存矩阵链 A[i..j]的最小代价
int divide[MAX][MAX] = {0};   // 记录最小代价ans[i,j]对应的分割点

/* 计算n元矩阵链p的最优代价
 * 动态规划的每一步结果储存在 ans与 divide中 */
void MatrixChainOrder(int p[], int n) {
    /* 初始化divide数组 */
    for (int i = 1; i <= n; i++)
        divide[i][i] = i;
    /* 矩阵链长度为2到n */
    for (int l = 2; l <= n; l++) {
        /* 讨论长度为l的矩阵链A[i..j] */
        for (int i = 1; i <= n - l + 1; i++) {
            int j = i + l - 1;
            ans[i][j] = INT_MAX;
            /* 在特定区间内:依次讨论每一个分割点d,将矩阵链A[i..j]分成A[i..d]和 A[d+1..j] */
            for (int temp, d = divide[i][j - 1]; d <= divide[i + 1][j]; d++) {
                temp = ans[i][d] + ans[d + 1][j] + p[i - 1] * p[d] * p[j];
                /* 记录下矩阵链A[i..j]最小的情况 */
                if (temp < ans[i][j]) {
                    ans[i][j] = temp;
                    divide[i][j] = d;
                }
            }
        }
    }
}

/* 根据divide数组,输出A[i..j]的最优情况 */
void PrintDivide(int i, int j) {
    if (i == j)
        printf("A%d", i);
    else {
        int d = divide[i][j];  //找到分界点
        printf("(");
        PrintDivide(i, d);
        PrintDivide(d + 1, j);
        printf(")");
    }
}

int main() {
    int n;
    scanf("%d", &n);
    int p[MAX];
    for (int temp, i = 0; i <= n; i++)
        scanf("%d", &p[i]);

    MatrixChainOrder(p, n);
    printf("%d\n", ans[1][n]);
    if (n == 1)
        printf("(A1)");
    else
        PrintDivide(1, n);
    printf("\n");
}



2. piedras consolidados

El problema piedras combinado: lineal dispuesto piedras apiladas N, la piedra es ahora fusionada en una pila. Establece lo siguiente: sólo se puede fusionar montones de grava adyacentes, montones de piedras lleva fecha de primera consolidación del número de pilas y piedras. El tiempo de mezcla buscan en N piedras apiladas costo mínimo pila. (N piedras en la pila, el número de piedras se almacenan en una matriz p_ {0..n-1}en)

 La siguiente es una n = 4, p = {4, 2, 3, 4} ejemplo, el tiempo mínimo que lleva a 26.


Esta cuestión es esencialmente un problema de multiplicación cadena matriz - elegir dos nodos adyacentes cada fusión de la cadena, hasta que toda la fusión se completa hasta el momento. El proceso combinado de piedra se encuentra entre corchetes en el proceso de la cadena de matriz.

Este problema es también un problema con una estructura de sub-óptima:

Con el fin de construir un montón de piedras p_ {0..n-1}óptimas soluciones combinadas, podemos descomponer el problema en dos sub-problemas:  \ Bg_white p_ {} i..d y  p_ {d + 1..n}piedras fusión. Después se obtiene la cuestión de la solución sub-óptima, entonces la solución sub-óptima al problema de combinar .

En busca de un programa dinámico para la solución recursiva:

El costo combinado de la de almacenamiento correspondiente en los ans matriz bidimensional [0..n-1, 0..n-  1] , hemos utilizado ans [i, j] representa un piedras pila combinados p_ {} i..j coste mínimo tiempo de recuento, por lo que el mínimo del problema original la consideración final en los ans de cálculo [1, n] en su interior. 

ecuación de transición de estados:

  • Cuando i = j cuando: \ Bg_white ans [i, j] = 0
  • Cuando i <j cuando: ans [i] [j] = min_ {i \ leq k <j} (ans [i] [k] + ans [k + 1] [j] + \ sum_ {i \ leq t \ leq j} p [t ])

 ps: cuando se define la matriz de la American National Standard todo inicializado a cero.


Código completa de CA 1: (sin optimizar O (n ^ 3)el tiempo de la complejidad)

El núcleo es un ciclo de tres parte

  • El primer bucle de capa: longitud l = 2..n
  • El segundo bucle de la capa: la discusión de cada piedras pila longitud l  p_ {} i..j: i = 1..n - l 1, j = i + l + 1
  • El tercer bucle de la capa: la determinación de una óptima dividiendo punto k = i..j-1

Verse, la complejidad del tiempo de este código O (n ^ 3)

#define N 100

#include <cstdio>
#include <climits>

/* 合并石子问题:线性排列着N堆石子,现在要将石子合并成一堆。
 * 规定如下:每次只能将相邻的两堆石子合并,合并两堆石子所花费的时间为两堆石子的数量和。
 * 求将N堆石子合并成一堆最小花费的时间。(石子分为n堆,石子的数量存储在数组p[0..n-1]中)*/
int ans[N][N] = {0};

int MergeStone(int p[], int n) {

    /* 石子堆的个数:从1到n */
    for (int l = 2; l <= n; l++) {
        /* 讨论l个石子的石子堆 p[i..j] */
        for (int i = 0; i < n - l + 1; i++) {
            int j = i + l - 1, sum = 0;
            /* 计算p[i..j]的石子总和 */
            for (int t = i; t <= j; t++)
                sum += p[t];
            ans[i][j] = INT_MAX;
           /* 依次讨论每一个分割点d:将石子堆p[i..j]分成p[i..k]和 A[k+1..j] */
            for (int temp, k = i; k < j; k++) {
                temp = ans[i][k] + ans[k + 1][j] + sum;
                if (temp < ans[i][j])
                    ans[i][j] = temp;
            }
        }
    }
    return ans[0][n - 1];
}

Completa Código AC 2: (optimización de la O (n ^ 2)complejidad del tiempo) 

#define N 100

#include <cstdio>
#include <climits>

/* 合并石子问题:线性排列着N堆石子,现在要将石子合并成一堆。
 * 规定如下:每次只能将相邻的两堆石子合并,合并两堆石子所花费的时间为两堆石子的数量和。
 * 求将N堆石子合并成一堆最小花费的时间。(石子分为n堆,石子的数量存储在数组p[0..n-1]中)*/

//优化版本!!!!

int ans[N][N] = {0};
int divide[N][N];

int MergeStone(int p[], int n) {
    /* divide数组初始化*/
    for (int i = 0; i < n; i++)
        divide[i][i] = i;

    /* 石子堆的个数:从1到n */
    for (int l = 2; l <= n; l++) {
        /* 讨论l个石子的石子堆 p[i..j] */
        for (int i = 0; i < n - l + 1; i++) {
            int j = i + l - 1, sum = 0;
            /* 计算p[i..j]的石子总和 */
            for (int t = i; t <= j; t++)
                sum += p[t];
            ans[i][j] = INT_MAX;
            /* 依次讨论特定区间内分割点d:将石子堆p[i..j]分成p[i..k]和 A[k+1..j] */
            for (int temp, k = divide[i][j - 1]; k <= divide[i + 1][j]; k++) {
                temp = ans[i][k] + ans[k + 1][j] + sum;
                if (temp < ans[i][j]) {
                    ans[i][j] = temp;
                    divide[i][j] = k;  //更新p[i..j]的石子堆的最优分割位置
                }

            }
        }
    }
    return ans[0][n - 1];
}

Tienen alguna pregunta por favor revise el intercambio, si lo desea este artículo poco útil de alabanza, ji, ji ~  



fin 

Sin atención personal bienvenida al público "  alitas de pollo Programación" , aquí es un código agrícola seria y de buen comportamiento.

---- haga lo er blogs más buen comportamiento, hacer el programador más sólida ----

Objetivos para escribir cuidadosamente cada artículo, por lo general agregados en notas empujará actualizaciones -

Aquí Insertar imagen Descripción

Publicados 138 artículos originales · ganado elogios 63 · Vistas a 10000 +

Supongo que te gusta

Origin blog.csdn.net/weixin_43787043/article/details/104965598
Recomendado
Clasificación