Matrix Chain Multiplication

Matrix-chain Multiplication

The goal of the matrix-chain multiplication problem is to find the most efficient way to multiply given n matrices M1,M2,M3,…,Mn.

Write a program which reads dimensions of Mi, and finds the minimum number of scalar multiplications to compute the maxrix-chain multiplication M1M2…Mn.

Input
In the first line, an integer n is given. In the following n lines, the dimension of matrix Mi (i=1…n) is given by two integers r and c which respectively represents the number of rows and columns of Mi.

Output
Print the minimum number of scalar multiplication in a line.

Constraints
1≤n≤100
1≤r,c≤100
Sample Input 1
6
30 35
35 15
15 5
5 10
10 20
20 25
Sample Output 1
15125
题意: 给定n个矩阵形成的矩阵链,求计算矩阵乘积M1M2M3…Mn时进行最少次标量相乘的运算顺序。
思路: 当求矩阵乘积M1M2M3…Mn时,可以把[1,n]内的矩阵分成两个区间[1,j]和[j+1,n],那么只要知道左区间相乘运算的结果和右区间相乘运算的结果,那么就可以左区间结果+右区间结果+P0* Pj * Pn就可以知道[1,n]的的结果。
这样只要知道所有左区间结果+右区间结果+P0* Pj *Pn的最小值就可以算出答案的最小值。
这样的话这样枚举所有的 j 就能找出最小值。
下一个问题就是求左区间和右区间,左右区间看成要求新的矩阵链式乘法(这里就说左区间,右区间同理),也就是求[1,j]区间的最小值,那么按照上面的思路就是求,新的两个区间[1,K]和[k+1,j]的最小值,并加上P0 * Pk *Pj,就是左区间的最小值。
通式就是求[i,j]区间的最小值,就是求出[i,k]+[k+1,j]+Pi-1 * Pk *Pj 的最小值。
解释一下,上面式子的Pi,是指矩阵的一个边的长度,读入数据的时候,读的是矩阵的行和列,所以用P[i]来表示。一个a✖b的矩阵乘以一个c✖d的矩阵,b必须等于c,成完后会变成a✖d的矩阵,运算结果就是a✖b✖d。所以会有后面关于P的公式
这也就是区间dp的思想
状态转移方程:
d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k + 1 ] [ j ] + P [ i − 1 ] ∗ P [ k ] ∗ P [ j ] ) ; dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+P[i-1]*P[k]*P[j]); dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+P[i1]P[k]P[j]);

 for(int i=1;i<=n;i++) dp[i][i]=0;  //一个矩阵,结果就是0
    for(int len=1;len<n;len++) {
               //枚举长度
        for(int i=1;i+len<=n;i++) {
           //枚举区间的左端点
            int j=i+len;                 //右端点
            dp[i][j]=inf;               //初始化为正无穷
            for(int k=i;k<=j-1;k++) {
       //枚举区间的分割点,从而求出这个区间的最小值
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+a[i-1]*a[k]*a[j]);
            }
        }
    }
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
const int N=110;
int a[N],n;
int dp[N][N];

int main() {
     
    cin>>n;
    for(int i=1;i<=n;i++) {
     
        cin>>a[i-1]>>a[i];
    }
    for(int i=1;i<=n;i++) dp[i][i]=0; 
    for(int len=1;len<n;len++) {
         
        for(int i=1;i+len<=n;i++) {
     
            int j=i+len;
            dp[i][j]=inf;
            for(int k=i;k<=j-1;k++) {
     
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+a[i-1]*a[k]*a[j]);
            }
        }
    }
    cout<<dp[1][n]<<endl;

    return 0;
} 

你可能感兴趣的:(算法,挑战程序设计竞赛,dp,区间dp)