最近看研三的找工作,主要变成题目都是过程实现,模拟一下,稍微带点技巧,算法层面也就是动态规划了,想想自己也一直忙于实验室各种事情,也该回来看看算法了,现在迁移一些以前写过的内容,顺便做复习。
矩阵链乘法也就为连续相乘的矩阵加括号,以最少的计算次数完成计算。即现有多个连续矩阵相乘A1A2A3...An,对于这样的n个矩阵相连,采取暴力法,按照排列组合在矩阵之间插入分隔符,可以选择的种类即有种。想必这样的方法是难以实现的,如果不会动归,都是采取空间搜索算法,遗传算法去做吧。
动态规划嘛,个人理解也就是无限贪心,打一张表,在改变一点结构后,总能找到上一个最优结构,即最优解是可以递归定义的,这里摘录一下算法导论上的原话:
如何制定动态规划方案:
1. 刻画一个最优解的结构特征
2. 递归的定义最优解的值
3. 计算最优解的值,通常采用自底向上方法
4. 利用计算出的信息构造出一个最优解
那么先从整体的角度来看,假设说前面的分割都非常优秀了,就差最后一步,需要在第k个位置进行切割,那么就是在A1-An之间选出一个k,之后计算过程为(A1A2...Ak)(Ak+1Ak+2...An)。那么在A1-Ak之间同样可以继续选k‘,那么,我们就可以列出式子:
其中m[i][j]表示Ai和Aj中间的最小计算次数,也就等于Ai和Ak之间的最小计算次数加上,Ak+1和Aj之间的最小计算次数,a[i].row*a[k].col*a[j].col也就是最后生成的左边矩阵a[i].row行(m1)乘a[k].row列(n1),右边矩阵a[k+1].row行(m2)乘a[j].col列(n2)的矩阵,左矩阵某一行乘右矩阵某一列是一个数字的计算次数,总共即有m1*n1*n2次乘法运算。
已经写出了递归式,我们开始计算最优解的值,采取自底向上方法,首先根据递归式,将M[i][i]全部填0。接下来设计自底向上填的方法。由递归式可以看出,我们要填写M[i][j]就需要知道M[i][k], M[k+1][j]举个例子M[2][4] 需要知道M[2][2],M[2][3], M[3][4], [m[4][4]。再举一个例子M[1][3],需要知道M[1][1], M[1][2], M[2][3], M[3][3]。
以五个元素为例,先画出填0的部分
m[1][1] m[2][2] m[3][3] m[4][4] m[5][5]
根据上图,现在考虑m[1][2],m[1][2]需要知道m[1][1],m[2][2], 那么m[2][3]需要知道m[2][2],m[3][3]。由此,m[3][4]需要知道m[3][3],m[4][4],补充上图
m[1][2] m[2][3] m[3][4] m[4][5]
m[1][1] m[2][2] m[3][3] m[4][4] m[5][5]
现在看这张图就感觉好一些了,那么跟着数字往上,现在考虑m[1][3],m[2][4],m[3][5],根据已经举过的数据,来继续画图
m[1][3] m[2][4] m[3][5]
m[1][2] m[2][3] m[3][4] m[4][5]
m[1][1] m[2][2] m[3][3] m[4][4] m[5][5]
可以看出来需要知道的数据是一个小三角形,很好推测,接下来的数据会是什么,那么画完这个大三角形吧
m[1][5]
m[1][4] m[2][5]
m[1][3] m[2][4] m[3][5]
m[1][2] m[2][3] m[3][4] m[4][5]
m[1][1] m[2][2] m[3][3] m[4][4] m[5][5]
根据递归式也能够看出这个结果。最优解就是m[1][5]的取值。
接下来考虑程序怎么编写,从最下面开始,填完了m[same][same]。
开始第二层,容易看出这一层m[i][j]之间j – i = 1,实际每一层都是有相同的数字差。这个数字差值在意义上也就是长度
那么我们设置一个变量就叫len,它的变化应该放在最外层循环中,循环n次(n表示矩阵数目)接下来循环变化的就是变量i了,i每次从1开始一直到n-len之后是j, j总是= i + len;
现在,遍历的循环任务就结束了,开始考虑如何计算,也就是怎么样做这个三角形。设置变量k,观察三角形,根据递归式,k的值就是从i-j,那么就这样设置了。根据递归式,可以轻松写下k这个最内层循环的内容,如此,这个程序核心部分就结束了,最后,贴上代码。
#define NUM 10
int M[NUM][NUM];
int S[NUM][NUM];
struct Matrix{
int x;
int y;
};
void Print(int i, int j)
{
if(i == j)
printf("A");
else
{
printf("(");
Print(i,S[i][j]);
Print(S[i][j]+1,j);
printf(")");
}
}
void Matrix_Chain_Order(struct Matrixa[NUM], int index_max)
{
unsigned int i,j,l,k,q;
unsigned int max_int = 0 - 1;
for(i = 0;i < index_max;++i )
M[i][i]= 0;
for(l = 1;l <= index_max; ++l) //length = l + 1;
for(i = 0;i <= index_max - l;++i)
{
j= i + l;
M[i][j]= max_int / 2;
for(k = i;k < j;++k)
{
q= M[i][k] + M[k+1][j] + a[i].x * a[k].y * a[j].y;
if(q < M[i][j])
{
M[i][j]= q;
S[i][j]= k;
}
}
}
Print(0, index_max);
printf("\n");
}
int main()
{
struct Matrix exc_ma[NUM];
int n;
int i, j;
scanf("%d",&n);
for(int i = 0;i < n; ++i)
scanf("%d%d",&exc_ma[i].x,&exc_ma[i].y);
Matrix_Chain_Order(exc_ma,--n);
}