AYITACM2016省赛第三周I - Optimal Array Multiplication Sequence(dp)

矩阵最少乘法


题意:

给你2个矩阵A、B,我们使用标准的矩阵相乘定义C=AB如下:

A阵列中栏(column)的数目一定要等于B阵列中列(row)的数目才可以做此2阵列的相乘。若我们以rows(A),columns(A)分别代表A阵列中列及栏的数目,要计算C阵列共需要的乘法的数目为:rows(A)*columns(B)*columns(A)。例如:A阵列是一个10x20的矩阵,B阵列是个20x15的矩阵,那么要算出C阵列需要做10*15*20,也就是3000次乘法。

要计算超过2个以上的矩阵相乘就得决定要用怎样的顺序来做。例如:X、Y、Z都是矩阵,要计算XYZ的话可以有2种选择:(XY)Z 或者X(YZ)。假设X是5x10的阵列,Y是10x20的阵列,Z是20x35的阵列,那个不同的运算顺序所需的乘法数会有不同:

(XY)Z

  • 5*20*10 = 1000次乘法完成(XY),并得到一5x20的阵列。
  • 5*35*20 = 3500次乘法得到最后的结果。
  • 总共需要的乘法的次数:1000+3500=4500。

X(YZ)

  • 10*35*20 = 7000次乘法完成(YZ),并得到一10x35的阵列。
  • 5*35*10 = 1750次乘法得到最后的结果。
  • 总共需要的乘法的次数:7000+1750=8750。

很明显的,我们可以知道计算(XY)Z会使用较少次的乘法。

这个问题是:给你一些矩阵,你要写一个程式来决定该如何相乘的顺序,使得用到乘法的次数会最少。

思路:最优矩阵链乘问题,典型的动态规划题目。


#include<stdio.h>
#define m 1000
#define inf 0x3f3f3f3f
int dp[m][m],s[m][m],p[m],n;
void print(int i,int j)//递归输出所有的结果
{
    if(i==j)
        printf("A%d",i); //输出是第几个数据
    else
    {
        printf("(");
        print(i,s[i][j]);//递归下一个数据
        printf(" x ");
        print(s[i][j]+1,j);
        printf(")");
    }
}
void work()
{
    int i,j,k,l,t;
    for(i=1; i<=n; i++)
        dp[i][i]=0;//首先初始化为0
    for(l=2; l<=n; l++)
        for(i=1; i<=n-l+1; i++)
        {
            j=i+l-1;         //判断i和j之间的最优解
            dp[i][j]=inf;
            for(k=i; k<=j-1; k++)
            {
                t=dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j];
                if(t<dp[i][j])
                {
                    dp[i][j]=t;  //保持最优解
                    s[i][j]=k; //记录需要加括号的地方
                }
            }
        }
    print(1,n); //输出i和j之间的最优解
   puts("");
}
int main()
{
    int c=1,i;
    while(scanf("%d",&n)&&n)
    {
        for(i=1; i<=n; i++)
            scanf("%d%d",&p[i-1],&p[i]);//输入数据
        printf("Case %d: ",c++);
        work();
    }
    return 0;
}


你可能感兴趣的:(AYITACM2016省赛第三周I - Optimal Array Multiplication Sequence(dp))