Intervalle DP | 1: Matrice des problèmes de la chaîne (optimisation y compris) - Exemple: matrice des pierres combinées de la chaîne

problème de la multiplication de la chaîne Matrix:  chaîne de matrice donnée de n <A1, A2, A3, ... , An>, la taille de la matrice Ai  p_ {i-1} \ cdot p_ {i} (0 \ leq i \ leq n) . système de crochets COMPLETE, de sorte que calculate A1A2 produit ... Un nombre minimum requis de multiplications scalaire.


annuaire

Tout d'abord, l'analyse de l'algorithme

1, les dispositifs supports les caractéristiques structurelles optimales

2, un programme récursif pour résoudre

En second lieu, l'algorithme

1, calculer le coût optimal

Optimisation de la Méthode d'écriture - complexité temporelle est O (n ^ 3)

La méthode optimisée - la complexité temporelle tombe O (n ^ 2)

2, assemblage solution optimale

Exemples Troisièmement,

1, problème de la multiplication des chaînes de matrice

Complet Code 1 AC :( complexité temporelle unoptimized  )O (n ^ 3) 

Code complet AC 2 :( optimisation de la complexité du temps  O (n ^ 2) 

2. pierres consolidées

Complet Code 1 AC :( complexité temporelle unoptimized )O (n ^ 3) 

Code complet AC 2 :( optimisation de la complexité du temps  O (n ^ 2) 

fin 



Lorsque seuls deux matrices A et B sont compatibles, à savoir, le nombre de colonnes égal au nombre de lignes A, B, peut multiplié. Si A est un p × q matrice, B est q × r matrice, le produit C est le p × matrice de r. C ont été calculées en PQR multiplications. Nous employons un certain nombre de fois multiplication pour représenter le coût de l' informatique

Pour plus d' matrice se multiplient sans cesse le problème, nous appelons les enjeux de la chaîne Matrix. La multiplication de matrices est associative, de sorte que toute méthode de parenthèses ne modifie pas le résultat d'une pluralité de multiplication de matrice. Cependant, différents entre parenthèses Schemes (modification de l' ordre de calcul) auront une incidence sur le calcul des coûts de la chaîne de multiplication de la matrice:


Tout d'abord, l'analyse de l'algorithme

1, les dispositifs supports les caractéristiques structurelles optimales

La première étape de la méthode de programmation dynamique est de trouver la sous-structure optimale, vous pouvez utiliser cette infrastructure, la solution optimale du problème initial de destructor optimal créer des problèmes.

(Pour plus de commodité, nous A_ {} i..j noterons A_iA_ {i + 1} ... A_jla matrice de résultat de la multiplication)

  • De toute Partielle apparence: une matrice pour chaque chaîne  A_ {} i..j, si leurs supports, nous devrions être en deux matrices Un det A_ {d + 1}divisée entre ouverte, nous allons discuter Aide}et A_ {d} + 1..jsupports de.
  • A partir de à l'ensemble locale Voir: le calcul A_ {} i..j coût = calculer le Aide}calcul coût +  A_ {d} + 1..j coût + calculé  le A_ {i..d} \ cdot A_ {d} + 1..jcoût.

Par conséquent, afin de construire une chaîne de matrice  A_ {} i..n solution problème de multiplication optimale, nous pouvons décomposer le problème en deux sous-problèmes:  Aide} et  l' A_ {d} + 1..n optimisation parenthèses problème. Après la question de la solution sous-optimale est obtenue, alors la solution sous-optimale du problème de la combinaison .


2, un programme récursif pour résoudre

  • La taille de la matrice correspondant à la stockée réseau à une dimension p [0..n]  , la matrice de a_i taille est  p_ {i-1} \ cdot p_ {i}.
  • Calcul du coût de la mémoire correspondante dans la matrice à deux dimensions ans [1..n, 1..n]  , nous avons utilisé ans [i, j] désigne une matrice  A_ {} i..j coût de calcul minimal, le coût de calcul du minimum du problème d' origine en finale ANS [ 1, n] à l'intérieur. 
  • point de division optimale correspondant au stocké à deux dimensions fracture de la matrice [1..n, 1..n]  , nous utilisons le clivage [i, j] enregistre les ans de coût optimal [i, j] correspondant au point de division optimal d. (Ce tableau est utile lors de l' impression de la structure optimale)

Selon les caractéristiques structurelles décrites ci-dessus du schéma optimal des supports, on peut citer l'équation de transition d'état:

  • Lorsque i = j lorsque: \ Bg_white ans [i, j] = 0
  • Quand i <j lorsque: ans[i, j] = min_{i\leq k< j} (ans[i, k] +ans[k+1,j] + p_{i-1}p_kp_j)

ps: lors de la définition du réseau SNA tous initialisés à zéro.


En second lieu, l'algorithme

1, calculer le coût optimal

L' analyse est connue de l'algorithme, les besoins en question à ascendantes méthodes: problème d'optimisation pour gérer la chaîne de sous-matrices, puis pris ensemble.

Alors, quand nous avons réalisé: Il devrait être la longueur de la matrice de la chaîne 2 a commencé à discuter, puis discuter de la longueur de la matrice de la chaîne 3 ... n la discussion finale de la longueur de la matrice de la chaîne, qui est d'obtenir une réponse sur cette base. Longuement a été déterminée en discussion, ne fuira pas le cas, ou aurait une incidence sur la valeur optimale.


Optimisation de la Méthode d'écriture - complexité temporelle est O (n ^ 3)

Ensuite , notre structure en boucle devrait ressembler à ceci:

  • La première boucle de couche: longueur L = 2..n
  • La deuxième boucle de couche: l'examen de chaque longueur de la matrice de la chaîne de l A_ {} i..j: i = 1..n - l 1, j = i + l + 1
  • La troisième boucle de couche: la détermination d'un point de division optimal 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;
                }
            }
        }
    }
}

La méthode optimisée - la complexité temporelle tombeO (n ^ 2) 

Trois méthodes de base au- dessus du cycle est inévitable, mais peut réduire considérablement le nombre de cycles pour traverser une troisième couche, de sorte que la complexité de temps est réduit O (n ^ 2) . Selon la chaîne matrice modèle les caractéristiques du problème, sa dynamique Solver peut utiliser l' optimisation des inégalités quadrangulaire . ( Les liens sont détaillés principe d'optimisation, la complexité temporelle du processus de certification)

Ainsi , les satisfait au point de décision optimal du relation: diviser [i] [j-1] \ leq clivage [i] [j] \ fracture leq [i + 1] [j]si nous troisième boucle de couche peut être optimisée de la manière suivante: Dans un intervalle particulier [ Divide [I] [J -1], Diviser [+ +1 i] [j] ] à l'intérieur de la traverse, laquelle plage de déplacement beaucoup moins que n.

ps: attention aux cas de limites, il est nécessaire de diviser le prêt initial.

/* 计算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, assemblage solution optimale

Dans le tableau on divise en deux dimensions [i, j] a été enregistrée dans  A_ {} i..j le point de coupe optimal, étant donné que la matrice de la chaîne de division optimale peut être décomposé en chaîne de division de sous-optimale, de sorte que l' on peut récursivement imprimé.

/* 根据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(")");
    }
}

Exemples Troisièmement,

1, problème de la multiplication des chaînes de matrice

réalisation dix le temps 2020 10 Mars Mardi, 07h55
rabais 0,8 Temps Discount 2020 mardi, 7 Avril 23h55
Autoriser fin aucun temps de fermeture 2020 mardi, 7 Avril 23h55

entrée:

Un total de deux lignes

La première rangée N (1 <= N <= 100), représentatif du nombre de matrices.

La seconde ligne comporte le nombre de N + 1, respectivement, A1, A2 ...... An + 1 (1 <= Ak <= 2000), Ak et Ak + 1 représente le k une matrice Ak X Ak + 1 en forme.

sortie:

Un total de deux lignes

La première ligne M, est le coût optimal. Note: le cas de test pour vous assurer que moins de 2 ^ M valeur 31

ordre optimal de la deuxième loi. Les, mais aussi les parenthèses les plus extérieures (A1 (A2A3) (A4)).

Note: Le test doit veiller à ce que la sortie de la semelle, donc il n'y a pas de situation de l'AAA.

  entrée test Résultats attendus délai mémoire limite processus supplémentaire
Test Case 1  
  1. 6↵
  2. 30 35 15 5 10 20 25↵
 
  1. 15125↵
  2. ((A1 (A2A3)) ((A4A5) A6)) ↵
1 seconde 64M

0

 


La méthode en détail spécifique a été expliqué ci-dessus, il ~

Principale Note: Lorsque le nombre de la matrice de la chaîne de la matrice pour produire un parenthésée, ou sera un wa.

Complete AC Code 1: (unoptimized O (n ^ 3)complexité temporelle)

//
// 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");
}


Complete AC Code 2: (optimisation de la O (n ^ 2)complexité du temps) 

//
// 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. pierres consolidées

Le problème des pierres combinées: linéaire arrangé pierres entassées N, Pierre est maintenant fusionné dans une pile. Il se lit comme suit: vous ne pouvez fusionner des tas de gravier adjacentes, des tas de pierres prend la consolidation temporelle du nombre de piles et de pierres. La fusion cherchent de temps en pierres N entassées coût minimum de pile. (N pierres dans la pile, le nombre de pierres sont stockées dans un tableau p_ {0..n-1}en)

 Ce qui suit est un n = 4, p = {4, 2, 3, 4} exemple, le temps minimum qu'il faut pour 26.


Cette question est essentiellement un problème de multiplication de la chaîne matricielle - choisir deux noeuds adjacents chaque fusion de la chaîne, jusqu'à ce que toute la fusion est terminée jusqu'à présent. Le procédé combiné de la pierre est placée entre crochets dans le processus de la chaîne de la matrice.

Ce problème est également un problème avec une structure sous-optimale:

Afin de construire un tas de pierres p_ {0..n-1}des solutions combinées, nous pouvons décomposer le problème en deux sous-problèmes:  \ Bg_white p_ {} i..d et  la p_ {d} + 1..nfusion des pierres. Après la question de la solution sous-optimale est obtenue, alors la solution sous-optimale du problème de la combinaison .

Vous cherchez un programme dynamique pour la résolution récursive:

Le coût combiné de stockage correspondants dans les ans de matrice à deux dimensions [0..n-1, 0..n-  1] , nous avons utilisé ans [i, j] représente une pierre de cheminée combinés p_ {} i..j coût d' un temps de comptage minimum, de sorte que le minimum du problème d' origine l'examen final dans les ans de calcul [1, n] à l'intérieur. 

équation de transition d'état:

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

 ps: lors de la définition du réseau SNA tous initialisés à zéro.


Complete AC Code 1: (unoptimized O (n ^ 3)complexité temporelle)

Le noyau est un cycle de trois parties

  • La première boucle de couche: longueur L = 2..n
  • La deuxième boucle de couche: l'examen de chaque longueur de pierres de pile l  p_ {} i..j: i = 1..n - l 1, j = i + l + 1
  • La troisième boucle de couche: la détermination d'un point de division optimal k = i..j-1

Être vu, la complexité temporelle de ce code 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];
}

Complete AC Code 2: (optimisation de la O (n ^ 2)complexité du temps) 

#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];
}

Toute question, veuillez examiner l'échange, si vous le souhaitez cet article peu utile de louange, hee hee ~  



fin 

Aucune attention de bienvenue personnelle au public «  ailes de poulet Programmation » , voici un code d' une agriculture sérieuse et bien élevé.

---- faire le blog le plus sage er, faire le plus programmeur solide ----

Vise à écrire soigneusement chaque article, généralement regroupées en notes poussera les mises à jour -

Insérer ici l'image Description

Publié 138 articles originaux · éloge de won 63 · vues 10000 +

Je suppose que tu aimes

Origine blog.csdn.net/weixin_43787043/article/details/104965598
conseillé
Classement