算法的基本思想和应用要点
动态规划算法与分治法类似,其基本思想是将待求解问题分成若干个子问题,先求解子问题的解得到原问题的解。与分治法不同的是,适合动态规划的问题经分解得到的往往不是互相独立的动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。
1.问题描述
1)给定n个矩阵{A1, A2,…, An}, 其中Ai 与 Ai+1 是可乘的, i = 1, 2, …, n-1
2)如何确定连乘积的计算次序,使得依次次序计算矩阵连乘积所需要的数乘次数最少
2.理论分析
1.矩阵乘法满足结合律
->矩阵乘法可以有不同的计算次序
矩阵连乘的计算次序可以用加括号的方式来确定
->若矩阵连乘已完全加括号,则其计算次序完全确定
3.完全加括号的矩阵连乘可递归定义为:
单个矩阵是完全加括号的;
矩阵连乘积A是完全加括号的,则A可表示为2个完全加
括号的矩阵连乘积B和C的乘积并加括号,即 A=(BC)。
- 矩阵A 和B可乘的条件是矩阵A的列数等于B的行数,若A是一个P*q矩阵,B是一个q*r矩阵,共需p*q*r次连乘。
- 具体例子将矩阵连乘积AiAi+1…Aj简记为A[i:j] ,这里i≤j。考察计算A[i:j]的最优计算次序。设这个计算次序在矩阵Ak和 Ak+1之间将矩阵链断开,i≤k<j,则其相应完全加括号方式为(AiAi+1…Ak)(Ak+1Ak+2…Aj)
-> A[i:j]的计算量:A[i:k]的计算量加上A[k+1:j]的计算量,再加上A[i:k]和A[k+1:j]相乘的计算量
案例:
package com.duo.test1;
class Matrix {
public static void MatrixChain(int[] p,int n, int[][] m, int[][] s) {
//计算出m[i][i]=0;(i=1,2,3,...n)
for (int i = 1; i <= n; i++) {
//System.out.println(i);
m[i][i] = 0;
}
//连乘的矩阵为两个及以上,自底向下依次遍历
for(int r = 2;r <= n; r++ ) {
for(int i = 1; i <= n-r+1; i++) {
int j = i+r-1;//右边界所在
//System.out.println(j);
m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];//断点为i时的最优值
s[i][j] = i;//断点为i
for(int k = i+1; k < j; k++) {//遍历断点从i+1开始到j
int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];//把断点为k时的最优值赋给t
if(t < m[i][j]) {
m[i][j] = t;//再把当前断点的最优值赋给m[i][j]
s[i][j] = k;//记录断点
}
}
}
}
}
public static void Traceback(int i, int j, int[][] s) {
//System.out.println("输出切割断点后计算次序");
if (i == j) {
// 递归出口
System.out.print("A"+i);
return;
} else {
System.out.print("(");
// 递归输出左边
Traceback(i, s[i][j], s);
// 递归输出右边
Traceback(s[i][j] + 1, j, s);
System.out.print(")");
}
}
public static void main(String[] args) {
System.out.println("代码功能测试:");
Matrix mc = new Matrix();
int n = 7;
int p[] = { 30, 35, 15, 5, 10, 20, 25 };
int m[][] = new int[n][n];
int s[][] = new int[n][n];
int l = p.length-1;
//System.out.println(l);
mc.MatrixChain(p, l,m, s);
System.out.println("输出A1到A6各个矩阵连乘的最优值:");
for (int i = 1; i < n; i++) {
for (int j = 1; j < n; j++) {
System.out.print(m[i][j] + "\t");
}
System.out.println();
}
System.out.println("输出实现最优值的各个断点:");
//输出实现最优值的各个断点
for (int i = 1; i < n; i++) {
for (int j = 1; j < n; j++) {
System.out.print(s[i][j]+" ");
}
System.out.println();
}
System.out.println("输出A1到A6的最优值计算次序:");
mc.Traceback( 1, 6, s);
}
}
总结:记录我的学习之旅!!!