动态规划算法
代码
import java.util.Scanner;
public class DP {
public static int matrixChaain(int []p, int [][]m, int [][]s){
// m[i][j]代表从第i到j之间的矩阵的最小连乘数
int n = p.length-1; // 当前矩阵的个数
for(int i=1;i<=n;i++) m[i][i]=0; //对角线的值初始化为0,单个矩阵之间自身连乘数为0
for(int r=2;r<=n;r++) // r代表连续r个矩阵之间的最小连乘数,之前初始化了1个矩阵之间的连乘,剩余2到n这几种情况
for(int i=1;i<=n-r+1;i++){ // i代表第i个矩阵
int j=i+r-1; // j代表第j个矩阵
m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j]; //m[i:j]=m[i:i]+m[i+1:j]
s[i][j]=i;
for(int k=i+1;k<j;k++){ // k代表从i到j中间进行分割
int t = m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(t<m[i][j]){
m[i][j]=t;
s[i][j]=k;
}
}
}
return m[1][n];
}
public static void main(String args[]) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int []p = new int[n+1];
for (int i = 0; i < n+1; i++) {
p[i]=scanner.nextInt();
}
System.out.println("矩阵最小连乘数为:"+matrixChaain(p,new int[n+1][n+1],new int [n+1][n+1]));
}
}
测试输入
6
30 35 15 5 10 20 25
测试输出
矩阵最小连乘数为:15125
运行结果
直接递归法
代码
import java.util.Scanner;
public class DG {
static int[] p;
static int[][] s;
public static int recurMatrixChain(int i,int j){
if(i==j)return 0;
int u = recurMatrixChain(i+1,j) + p[i-1]*p[i]*p[j];
s[i][j]=i;
for(int k=i+1;k<j;k++){
int t = recurMatrixChain(i,k)+recurMatrixChain(k+1,j) + p[i-1]*p[k]*p[j];
if(t<u){
u=t;
s[i][j]=k;
}
}
return u;
}
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
p = new int[n + 1];
s = new int[n+1][n+1];
for (int i = 0; i < n + 1; i++) {
p[i] = scanner.nextInt();
}
System.out.println("矩阵最小连乘数为:" +recurMatrixChain(1,5));
}
}
测试输入
6
30 35 15 5 10 20 25
测试输出
矩阵最小连乘数为:15125
运行结果
备忘录方法
代码
import java.util.Scanner;
public class BWL {
static int[] p;
static int[][] s;
static int[][] m;
public static int lookupChain(int i,int j){
if(m[i][j]>0) return m[i][j];
if(i==j) return 0;
int u = lookupChain(i+1,j)+p[i-1]*p[i]*p[j];
s[i][j] = i;
for(int k=i+1;k<j;k++){
int t = lookupChain(i,k)+lookupChain(k+1,j)+p[i-1]*p[k]*p[j];
if(t<u){
u=t;
s[i][j]=k;
}
}
m[i][j]=u;
return u;
}
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
p = new int[n + 1];
s = new int[n + 1][n + 1];
m = new int[n + 1][n + 1];
for (int i = 0; i < n + 1; i++) {
p[i] = scanner.nextInt();
}
System.out.println("矩阵最小连乘数为:" + lookupChain(1, 6));
}
}
测试输入
6
30 35 15 5 10 20 25
测试输出
矩阵最小连乘数为:15125
运行结果
实验总结
动态规划的基本思想是,将原问题拆分为若干子问题,自底向上的求解。其总是充分利用重叠子问题,即通过每个子问题只解一次,把解保存在一个表中,巧妙的避免了子问题的重复求解。
递归方法,采用的是自顶向下的思想,拆分为若干子问题,但是造成了子问题的重复求解。
备忘录方法,采用的也是自顶向下的思想,但是该方法维护了一个记录子问题解的表,虽然填表动作的控制结构更像递归方法,但是的确避免了子问题的重复求解。相当于解决了使用递归造成的子问题重复求解问题
动态规划算法的基本要素:
1、最优子结构性质:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。
2、重叠子问题性质:动态规划算法对每个问题只解一次,将其解保存在一个表格中,当再次需要解此问题时,用常数时间查看一下结果。因此,用动态规划算法通常只需要多项式时间。
备忘录方法:
•用一个表格来保存已解决的子问题的答案,用的时候查表即可。
•采用的递归方式是自顶向下。
•控制结构与直接递归相同,区别在于备忘录方式为每个解过的子问题建立备忘录。
•初始化为每个子问题的记录存入一个特殊的值,表示并未求解。在求解过程中,查看相应记录如果是特殊值,表示未求解,否则只要取出该子问题的解答即可。
备忘录方法与动态规划和递归的区别:
1、动态规划是自低向上 ,备忘录方法是自顶向下,递归是自顶向下
2、动态规划每个子问题都要解一次,但不会求解重复子问题;备忘录方法只解哪些确实需要解的子问题;递归方法每个子问题都要解一次,包括重复子问题• 。