填坑填坑,动态规划第二篇,想写矩阵连乘问题。
问题描述:
这个问题描述有点复杂,放张图解释:
也就是选择最优的计算次序,以求乘法次数最少。
问题分析:
这里也可以采用自底向上的思路。每个子问题的最后一步一定是两个矩阵相乘。
现在假设要求的是A1 * A2 * A3 * … * An的最优计算次序,第 i 个矩阵为( mi-1*mi )矩阵,我们取中间连续的一段,从Ai 到 Aj 作为子问题,记M(i , j)为其最优解。则M(i , j)=min{ M(i , k)+M(k+1 , j)+mi-1 * mk * mj },且 i <= k < j。
接下来要写算法我们要确定两个问题,初始化和循环要怎么写。
这里引入一维数组m记录矩阵的行列数,二维数组M记录最优解。由于M[ j , j ]意味着只有一个矩阵,所以M[ j , j ] 都初始化为0 。
循环的写法,菜鸡的我觉得乍一看别人的代码有点难理解,于是我试着填表M( i , j )(填表其实也就是动态规划的记忆过程)。在填表过程中,会发现①其实只用算这个n*n表的对角线的上半部分或下半部分(这里填的是上半部分),②计算是有顺序的。
譬如我要算图中例子的M(1 , 4),M(1 , 4)=min{M(1,1)+M(2,4)+m0*m1*m4,M(1,2)+M(3,4)+m0*m2*m4,M(1,3)+M(4,4)+m0*m3*m4} 就会发现要先算M(2,4),M(1,2),M(3,4),M(1,3)。具体的顺序自己写一下就知道了。
这里只放循环部分的源代码:
for(int s=1;s<=n;s++){
for(int i=1;i<=n-s;i++){
j=i+s;
//初始化
int t=Integer.MAX_VALUE;
for(int k=i;k<j;k++){
temp=M[i][k]+M[k+1][j]+m[i-1]*m[k]*m[j];
if(temp<t){
t=temp;
M[i][j]=temp;
// System.out.println(i+","+k+","+j);
// System.out.println(M[i][k]+"+"+M[k+1][j]+"+"+m[i-1]*m[k]*m[j]);
}
}
}
}
System.out.println(M[1][n]);
课上老师还提了个问题,能不能不引入s,只用 i 和 j 就写好这个循环,之后可以再思考下。