Aprendendo "Introdução aos Algoritmos" (18) - multiplicação em cadeia de matrizes de programação dinâmica (linguagem C)


prefácio

Este artigo explica principalmente o problema de multiplicação de cadeias de matrizes em programação dinâmica: dada uma cadeia de matrizes, obtenha sua ordem de cálculo de custo mínimo. A análise do esquema de programação dinâmica é fornecida e a implementação da linguagem C é fornecida.


1. Multiplicação em cadeia de matrizes

1. Descrição do problema

Dada uma sequência (cadeia de matrizes) de n matrizes < A 1 , A 2 , A 3 , A 4 , . . . , A n > <A_1,A_2,A_3,A_4,...,A_n><A1,A2,A3,A4,... ,Anão> , agora queremos calcular seu produto
A 1 A 2 A 3 A 4 . . . A n A_1 A_2A_3A_4...A_nA1A2A3A4... Umnão
Para multiplicação em cadeia de matrizes, podemos determinar quais duas matrizes multiplicar primeiro adicionando parênteses. Independentemente da ordem de multiplicação, isso não afeta o resultado final.
Porém, para a multiplicação de matrizes entre ordens diferentes, o computador tem que pagar um preço completamente diferente.
Por exemplo < A 1 , A 2 , A 3 > , onde A 1 é 2 ∗ 3; A 2 é 3 ∗ 4; A 3 é 4 ∗ 1 <A_1,A_2,A_3>, onde A_1 é 2*3; A_2 é 3*4; A_3 é 4*1<A1,A2,A3>,onde A1por 23 ; A2por 34 ; A3para 41
Podemos calcular o custo de corte de duas estratégias diferentes:

  • ( (A 1 A 2 ) A 3 ) = 2 ∗ 3 ∗ 4 + 2 ∗ 4 ∗ 1 = 32 ((A_1A_2)A_3)=2*3*4+2*4*1=32(( Um1A2) UMA3)=234+241=32
  • (A 1 ( A 2 A 3 ) ) = 3 ∗ 4 ∗ 1 + 2 ∗ 3 ∗ 1 = 18 (A_1(A_2A_3))=3*4*1+2*3*1=18( Uma1( Uma2A3))=341+231=18

Obviamente, os dois custos são completamente diferentes. Agora nosso problema éDada uma cadeia matricial, obtenha sua ordem de cálculo de custo mínimo

2. Resolução de problemas

1. Estrutura ideal de subproblemas

Primeiro fornecemos a fórmula de solução recursiva correspondente diretamente:
w [ i , j ] = { 0 if i = jmin { w [ i , k ] + w [ k + 1 , j ] + pi − 1 pkpj } se i < jw [ i,j]=\begin{casos} 0& \text{ if }i=j \\ min\{ w[i,k]+w[k+1,j]+p_{i-1}p_kp_j\} & \text{ if } i<j \\ \end{casos}eu [ eu ,j ]={ 0min { w [ eu ,k ]+w [ k+1 ,j ]+peu 1pkpj} se  eu=j se  eu<j

  • w[i,j] representa o custo mínimo da cadeia de matrizes no caminho da i-ésima matriz para a j-ésima matriz
  • pi − 1 pkpj p_{i-1}p_kp_jpeu 1pkpjRepresenta o custo necessário para construir de uma subsolução ideal até sua solução pai ideal

2. Programação dinâmica

Usamos uma matriz bidimensional para registrar a solução ótima para os subproblemas. Por exemplo, a solução ótima de w[2,4] é registrada na matriz w[1,3] (porque a matriz começa em 0).
Ao mesmo tempo, começamos a encontrar a solução ótima da cadeia de submatrizes com comprimento de 2 e, em seguida, aumentamos o comprimento em 1 até finalmente obtermos a solução ótima da cadeia de n-matrizes.
Este processo usa um ciclo de três camadas

  • A primeira camada de loop atravessa o comprimento da cadeia de matriz de pequeno a grande
  • A segunda camada percorre o loop da primeira camada para determinar a posição da primeira matriz na cadeia de submatrizes sob o comprimento
  • A terceira camada percorre todos os esquemas de "corte" da cadeia de matrizes determinados pelos dois primeiros loops

3. Construção de solução ideal

Após o loop de programação dinâmica de três camadas, podemos agora obter o valor específico do custo mínimo, mas qual é a ordem específica de multiplicação da matriz, precisamos construir a solução ótima.
Usamos um grupo de números bidimensionais para nos ajudar na construção da solução ótima.

  • Usamos s[0,6] para registrar a primeira posição entre parênteses da cadeia de matrizes w[1,7], ou seja, seu valor k.
  • Registramos o valor ideal de k para a cadeia de matrizes para todos os casos.
  • Então, chamando o algoritmo recursivamente, os resultados de saída entre parênteses podem ser obtidos. Para obter detalhes, consulte o código abaixo. Os leitores também podem determinar rapidamente a solução desenhando uma árvore recursiva.

Três, código C

1. Código

#include<stdio.h>
#include<stdlib.h>
#include<time.h>



//由于有n个矩阵链乘
//需要n+1个存储单元来存储行列信息
//此处SIZE为存储单元的个数
//因此矩阵链乘的个数是SIZE-1 
#define SIZE 10
//此处可以规定矩阵的行列数为1~LIM的随机数 
#define LIM 100
//注意:
//由于计算机存储数大小的限制
//SIZE和LIM不宜过大
//过大肯定会使得程序崩溃 



int Matrix_chain_order(int *p,int s[][SIZE-1],int w[][SIZE-1],int size)
{
    
    
	int i=0;
	int j=0;
	int k=0;
	int q=0;
	int l=0;
	int r=0;
	for(i=0;i<size-1;i++)
	{
    
    
		w[i][i]=0;
		s[i][i]=0;
	}
	for(i=2;i<=(size-1);i++)
	{
    
    
		for(j=1;j<=(size-i);j++)
		{
    
    
			l=j;
			r=j+i-1;
			w[l-1][r-1]=10000000;
			for(k=l;k<r;k++)
			{
    
    
				q=w[l-1][k-1]+w[k][r-1]+p[l-1]*p[k]*p[r];
				if(q<w[l-1][r-1])
				{
    
    
					w[l-1][r-1]=q;
					s[l-1][r-1]=k;
				}
			}
		}
	}
	return w[0][size-2];
}



void print_priority(int s[][SIZE-1],int l,int r)
{
    
    
	if(l==r)
	{
    
    
		printf("A%d",l+1);
		return;
	}
	printf("(");
	print_priority(s,l,s[l][r]-1);
	print_priority(s,s[l][r],r);
	printf(")");		
}



int main()
{
    
    
	int p[SIZE];
	int s[SIZE-1][SIZE-1];
	int w[SIZE-1][SIZE-1];
	int min_pay;
	int i=0;
	int j=0;
	srand((unsigned)time(NULL));
	for(i=0;i<SIZE;i++)
	{
    
    
		p[i]=rand()%LIM+1;
	}
	for(i=0;i<SIZE;i++)
	{
    
    
		printf("%5d",p[i]);
	}
	printf("\n");
	min_pay=Matrix_chain_order(p,s,w,SIZE);
	printf("%5d\n",min_pay);
	print_priority(s,0,SIZE-2);
	return 0;
} 

2. Resultados

insira a descrição da imagem aqui


Resumir

Os leitores podem me corrigir se houver alguma inadequação no artigo.
Para outras questões sobre programação dinâmica, você também pode consultar:
Aprendizagem "Introdução aos Algoritmos" (17) ---- Programação Dinâmica Corte de Tiras de Aço (Linguagem C)

Acho que você gosta

Origin blog.csdn.net/weixin_52042488/article/details/127147710
Recomendado
Clasificación