给定一个n个矩阵的序列
考虑矩阵链
如果按
如果按
为了得到所需乘法次数最少的方案,需要计算所有种方案的代价。
对一个n个矩阵的链,令P(n) 表示可供选择的括号化方案的数量。
完全括号化方案的矩阵乘积可以描述为两个完全括号化的部分相乘的形式,
k为分割点,即第k个矩阵和第k+1个矩阵之间
可以看出括号化方案的数量与n呈指数关系
由于要求得矩阵链
令
当
当
即:
递归算法会多次遇到同一个子问题,与钢铁切割很类似,每一次高层的运算,都会调用底层结果,越是底层,被调用的次数越多。所以可以采用自底向上的方法,先对底层逐个求解,当上层需要调用底层时,底层已经被求解完毕。
用m[i][j]二维矩阵保存对应链
用s[i][j]二维矩阵保存对应链
void Matrix_Chain_Order(int p[],int n)
{
int i,j,L,k,q;
for (i=1;i<=n;i++) //先对单个矩阵的链,求解,即所有m[i][i] =0;
{
m[i][i]=0;
}
for(L=2;L<=n;L++) //从两个矩阵链的长度开始,逐次增加矩阵链的长度
for(i=1;i<=n-L+1;i++) //在给定p[]中的矩阵链中,对所有种长度为L的情况计算
{
j = i+L-1;
m[i][j] = -1;
for(k=i;k<=j-1;k++) //遍历所有可能的划分点k,计算出最优的划分方案
{
q = m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];//计算划分的代价
if ( q < m[i][j] || m[i][j] == -1)
{
m[i][j] = q; //最优的代价q保存在m[i][j]中
s[i][j] = k; //最优的划分位置k保存在s[i][j]中
}
}
}
}
矩阵链
/************************************************************************
CSDN 勿在浮沙筑高台
http://blog.csdn.net/luoshixian099
算法导论--动态规划(矩阵链乘法)
2015年6月3日
************************************************************************/
#include <STDIO.H>
#include <STDLIB.H>
int m[7][7]={0};
int s[7][7]={0};
void Print_Optimal_Parens(int s[][7],int i,int j) //构造最优解
{
if ( i ==j)
{
printf("A%d",i);
}
else
{
printf("(");
Print_Optimal_Parens(s,i,s[i][j]);
Print_Optimal_Parens(s,s[i][j]+1,j);
printf(")");
}
}
void Matrix_Chain_Order(int p[],int n)
{
int i,j,L,k,q;
for (i=1;i<=n;i++) //先对单个矩阵的链,求解,即所有m[i][i] =0;
{
m[i][i]=0;
}
for(L=2;L<=n;L++) //从两个矩阵链开始,逐次增加矩阵链的长度
for(i=1;i<=n-L+1;i++) //在给定p[]中的矩阵链中,对所有种长度为L的情况计算
{
j = i+L-1;
m[i][j] = -1;
for(k=i;k<=j-1;k++) //遍历所有可能的划分点k,计算出最优的划分方案,
{
q = m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if ( q < m[i][j] || m[i][j] == -1)
{
m[i][j] = q; //最优的代价q保存在m[i][j]中
s[i][j] = k; //最优的划分位置k保存在s[i][j]中
}
}
}
}
void main()
{
int p[]={30,35,15,5,10,20,25}; //矩阵的输入
int length = sizeof(p)/sizeof(p[0])-1; //矩阵长度
int i,j;
Matrix_Chain_Order(p,length);
for(i =1;i<=6;i++)
{
for (j=1;j<=6;j++)
{
printf("%8d",m[i][j]);
}
printf("\n");
}
Print_Optimal_Parens(s,1,6);
printf("\n");
}
原文地址:http://blog.csdn.net/luoshixian099/article/details/46344175