动态规划算法(1)--矩阵连乘

目录

一、动态数组

1、创建动态数组

2、添加元素

3、删除修改元素

4、访问元素 

5、返回数组长度

6、for each遍历数组 

二、输入多个数字 

1、正则表达式

2、has.next()方法

三、矩阵连乘

1、什么是矩阵连乘?

2、动态规划思路

3、手推m和s矩阵

4、完整代码

5、备忘录方法


一、动态数组

1、创建动态数组

        创建动态数组ArrayList,先调用ArrayList库,之后动态创建语句如下,括号内填写数组元素个数,不知道可以不填。

    import java.util.ArrayList;
    ArrayList num = new ArrayList<>();

2、添加元素

        使用函数add添加元素。如:添加元素1。

    num.add(1);

        如果创建一个ArrayList num与list1相同(num和list1同为ArrayList类型)

    ArrayList num = new ArrayList<>(list1);

3、删除修改元素

       使用函数remove删除特定索引的元素。如:删除索引为1的元素。

    num.remove(1);

        使用函数set修改特定索引的元素。如:将索引为1的元素修改为"java"。

    num.set(1,"java");

4、访问元素 

        使用函数get返回特定索引的元素。如:返回索引1的元素并打印。

    system.out.println(num.get(1));

5、返回数组长度

        使用函数size()返回数组长度。如:返回数组num长度并打印

    system.out.println(num.size())

6、for each遍历数组 

        i是遍历的数组每一个值,num是数组名。

    for(int i:num)
    {
        System.out.println(i);
    }

二、输入多个数字 

1、正则表达式

        不需要import其他的东西。输入一串以空格为间隔的数字,字符串形式,经过正则表达式拆解,存入num动态数组中。

        如果数字之间以逗号为间隔,则需要将匹配改为",\\s+"。

    import java.util.ArrayList;
    ArrayList num = new ArrayList<>();
    String input= new Scanner(System.in).nextLine();
    String[] numbers=input.split("\\s+");
    for (String number : numbers) 
        {
            num.add(Integer.parseInt(number));
        }

2、has.next()方法

        该方法存在弊端,不能退出循环。

    import java.util.ArrayList;
    ArrayList num = new ArrayList<>();
    Scanner scanner=new Scanner(System.in);
    int n;
    int[] num;
        
    while(scanner.hasNext()) {
         n=scanner.nextInt();
         num.add(n);
    }

三、矩阵连乘

1、什么是矩阵连乘?

        不同的结合方式,可以导致不同的数乘次数,因为乘法远大于加法量级,所以加法可以忽视。那什么样的括号选择是可以获得最少的数乘次数呢?

动态规划算法(1)--矩阵连乘_第1张图片

        如果一味的进行枚举,寻找最优的数乘次数需要指数级复杂度。显然这种方式,在较大的个数面前利用计算机是不能解决的。

动态规划算法(1)--矩阵连乘_第2张图片

2、动态规划思路

(1)首先定义几个结构,以便后续进行理解。

        A[1:n],代表1到n个矩阵的连乘积。

        A[i:j]的最少数乘次数记为m[i][j]。

        p数组为矩阵链的值。比如30*35和35*15两个矩阵的矩阵链为30,35,15。

        s数组记录断开位置。

(2)矩阵连乘遵循最优子结构,也就是说矩阵连乘的各子结构都是最优的。

        假设A[1:4]的最优子结构是 (A_1A_2)(A_3A_4) ,那么A[1:2]的最优子结构一定是(A_1A_2)

        根据上面两条,我们能得出A[i:j]的最少数乘次数记为m[i][j],

动态规划算法(1)--矩阵连乘_第3张图片

3、手推m和s矩阵

        m矩阵和s矩阵几乎同步计算,仅保留上三角形,主对角线均为全0,依次按对角线进行计算,每计算完一条对角线向右上平移一条对角线。

动态规划算法(1)--矩阵连乘_第4张图片

        下面给出m[1][3]和s[1][3]的计算,可以看到从1断开(A_1(A_2A_3))小于从2分割((A_1A_2)A_3)的值,所以m[1][3]选择较小者7875,s[1][3]=1。

动态规划算法(1)--矩阵连乘_第5张图片

        如果求解A[1:6]的最优解的匹配方式,倒序执行上面s步骤。

4、完整代码

import java.util.Scanner;
import java.util.ArrayList;
public class matrixplusnew {
    public static void main(String[] args)
    {
        ArrayList num = new ArrayList<>();
        String input= new Scanner(System.in).nextLine();
        String[] numbers=input.split("\\s+");
        for (String number : numbers) 
        {
            num.add(Integer.parseInt(number));
        }

        int size=num.size()-1;
        //6*6
        int [][] m=new int[size+1][size+1];
        int [][] s=new int[size+1][size+1];
        MatrixChain(num,m,s);
        //输出m数组
        for(int i=1;ip,int [][]m,int [][]s) {
		int n = p.size() - 1;
		for (int i = 1; i <= n; 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;    //这个位置非常巧妙,可以确保对角线依次执行
				m[i][j] = m[i + 1][j] + p.get(i - 1) * p.get(i) * p.get(j);//由于第二条对角线,依赖于第一条对角线计算m[i][i],m[i][i]值为0,故省略。
				s[i][j] = i;

				for (int k = i + 1; k < j; k++)
                 {
					int t = m[i][k] + m[k + 1][j] + p.get(i - 1) * p.get(k) * p.get(j);
					if (t < m[i][j]) 
                    {
						m[i][j] = t;
						s[i][j] = k;
					}
				}
			}
		}
    }
    //获得括号匹配方式
    private static void Traceback(int i,int j,int[][]s)
    {
        if(i==j)
            return;
        Traceback(i, s[i][j],s);    //单独写每两个子结构的最优解,可以供读者合成匹配方式
        Traceback(s[i][j]+1,j,s);
        System.out.print("A"+i+", "+s[i][j]);
        System.out.println(" and A"+(s[i][j]+1)+", "+j);
    }
}

5、备忘录方法

        备忘录算法自顶向下计算,但他不够灵活,每次计算完整矩阵链的最优次序。其中p,m数组都为类外数组,所有函数均可使用。通过减少重复计算,减少时间复杂度。

动态规划算法(1)--矩阵连乘_第6张图片

public static int memoizedmatrixChain(int n){
	for (int i=0;i<=n;i++){
		for(int j=0;j<=n;j++){
			m[i][j]=0;
		}
	}//初始化备忘录数组
	return lookupChain(1,n);
}
public static lookupChain(int i,int j){
	if(m[i][j]>0)
		return m[i][j];//如果该项子问题有记录,返回该记录
	if(i==j)
		return 0;//如果相乘的两个矩阵相等,则返回0
	int u=lookupChain(i+1,j)+p[i-1]*p[i]p[j];//递归调用
	s[i][j]=i;//存储最佳断点
	for(int k=i+1;k

你可能感兴趣的:(算法设计,java,算法,动态规划)