• 矩阵最优连乘问题(区间DP+记忆化)


    Description

    在科学计算中经常要计算矩阵的乘积。矩阵A和B可乘的条件是矩阵A的列数等于矩阵B的行数。若A是一个p×q的矩阵,B是一个q×r的矩阵,则其乘积C=AB是一个p×r的矩阵。

    由公式知计算C=AB总共需要pqr次的数乘。

    为了说明在计算矩阵连乘积时加括号方式对整个计算量的影响,我们来看一个计算3个矩阵{A1,A2,A3}的连乘积的例子。设这3个矩阵的维数分别为10×100,100×5和5×50。若按第一种加括号方式((A1A2)A3)来计算,总共需要10×100×5+10×5×50=7500次的数乘。若按第二种加括号方式(A1(A2A3))来计算,则需要的数乘次数为100×5×50+10×100×50=75000。第二种加括号方式的计算量是第一种加括号方式的计算量的10倍。由此可见,在计算矩阵连乘积时,加括号方式,即计算次序对计算量有很大影响。

    于是,人们自然会提出矩阵连乘积的最优计算次序问题,即对于给定的相继n个矩阵{A1,A2,…,An}(其中Ai的维数为pi-1×pi ,i=1,2,…,n),如何确定计算矩阵连乘积A1A2…An的一个计算次序(完全加括号方式),使得依此次序计算矩阵连乘积需要的数乘次数最少。

    输入数据第一行为矩阵个数,第二行为n+1个数字a[0~n],其中对于第i个矩阵其大小为a[i-1]*a[i]。

    刚刚学习了区间DP,写发题解纪念一下。

    按照区间DP的思想,可以倒着分析,枚举最后一次进行乘法的位置,将原区间转化为两个子区间,相应代表了将原问题转化为两个规模较小的子问题。这里可以将递归和记忆化结合起来,递归的终点就是区间左端点等于右端点,由于提前给dp[i][i]赋值为0,所以这里直接return 0;同时如果dp[l][r]不为初始化时的0x3f3f3f3f的话说明这个值已经得到了就不用再算一遍了,直接return就好(记忆化)。然后就是dp[l][r]还没被计算过,那么枚举每个可能为当前区间最后一次做乘法的位置:l~r-1,然后写转移方程dp[l][r]=min(dp[l][r],process(l,i)+process(i+1,r)+a[l-1]*a[i]*a[r])(注意这里的dp[l][r]不要写成process(l,r)要不然永远无法更新,直接死循环了),至于为啥加的是a[l-1]*a[i]*a[r],这是根据矩阵乘法的性质得来的,分开的左半个矩阵的大小为a[l-1]*a[i],右半个矩阵的大小为a[i]*a[r],算出来后直接return即可。最终要求的就是process(1,n)。

    #include <bits/stdc++.h>
    using namespace std;
    int n,a[1005];//第i个矩阵是a[i-1]*a[i]大小 
    int dp[1005][1005]={0};
    int process(int l,int r)
    {
        if(dp[l][r]!=0x3f3f3f3f)return dp[l][r];
        int i;
        for(i=l;i<r;i++)
        {
            dp[l][r]=min(dp[l][r],process(l,i)+process(i+1,r)+a[l-1]*a[i]*a[r]);//这里的dp[l][r]不要写成process(l,r)要不然永远无法更新,直接死循环了 
        }
        return dp[l][r];
    }
    int main()
    {
        cin>>n;
        int i;
        for(i=0;i<=n;i++)scanf("%d",&a[i]);
        memset(dp,0x3f3f3f3f,sizeof(dp));
        for(i=1;i<=n;i++)dp[i][i]=0;
        printf("%d",process(1,n));
        return 0;
    }
  • 相关阅读:
    Java8新特性2 lambda表达式
    Java8新特性1
    多线程与高并发(2)Volatile+CAS
    多线程与高并发 Synchronize
    《重构:改善既有代码的设计》读书笔记5 简化函数调用
    《重构:改善既有代码的设计》读书笔记4 简化条件表达式
    mysql语法大全使用篇
    《重构:改善既有代码的设计》读书笔记3 重新组织数据
    《重构:改善既有代码的设计》读书笔记2 在对象之间搬移特性
    《重构:改善既有代码的设计》读书笔记1——重新组织函数
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/12506902.html
Copyright © 2020-2023  润新知