动态规划之矩阵链乘法

问题描述与分析:

给定n个矩阵的序列,(A1,A2…An),我们希望计算他们的乘积
A1*A2..*An
例如如果矩阵链为(A1 A2 A3 A4 ) 那么共有五种完全括号化的形式:
这里写图片描述

这里写图片描述

运用动态规划方法:

第一步:寻找最优子结构,为了对AiAi+1..Aj 进行括号化,假设最优括号化方案在  Ak,Ak+1之间,则首先计算 Ai..k和Ak+1..Aj 

第二步:一个递归求解方案,令m[i,j]为Ai...j所需标量乘法的最小值
即
m[i,j]=m[i,k]+m[k+1,j]+pi-1*pk*pj

矩阵 Ai 的大小 为 pi-1*pi

第三步:  计算最优代价:

void matrix_chain_order(int *p, int len, int m[N + 1][N + 1], int s[N + 1][N + 1])
{
         int i, j, k, t;
         for (i = 0; i <= N; ++i)
                 m[i][i] = 0;
         for (t = 2; t <= N; t++)  //当前链乘矩阵的长度
             {
                 for (i = 1; i <= N - t + 1; i++)  //从第一矩阵开始算起,计算长度为t的最少代价
                     {
                        j = i + t - 1;//长度为t时候的最后一个元素
                         m[i][j] = MAXVALUE;  //初始化为最大代价
                     for (k = i; k <= j - 1; k++)   //寻找最优的k值,使得分成两部分k在i与j-1之间
                             {
                                 int temp = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];
                                 if (temp < m[i][j])
                                     {
                                         m[i][j] = temp;   //记录下当前的最小代价
                                        s[i][j] = k;      //记录当前的括号位置,即矩阵的编号
                                     }
                            }
                     }
             }
     }

下面实现示例:

p={30*35,35*15,15*5,5*10,10*20,20*25};
N=6;

#include <iostream>
 using namespace std;
 #define N 6
 #define MAXVALUE 1000000

 void matrix_chain_order(int *p, int len, int m[N + 1][N + 1], int s[N + 1][N + 1]);
void print_optimal_parents(int s[N + 1][N + 1], int i, int j);

 int main()
 {
         int p[N + 1] = { 30,35,15,5,10,20,25 };
         int m[N + 1][N + 1] = { 0 };
         int s[N + 1][N + 1] = { 0 };
         int i, j;
         matrix_chain_order(p, N + 1, m, s);
         cout << "m value is: " << endl;
         for (i = 1; i <= N; ++i)
            {
                for (j = 1; j <= N; ++j)
                         cout << m[i][j] << " ";
                 cout << endl;
            }
       cout << "s value is: " << endl;
         for (i = 1; i <= N; ++i)
            {
                for (j = 1; j <= N; ++j)
                        cout << s[i][j] << " ";
                cout << endl;
            }
        cout << "The result is:" << endl;
         print_optimal_parents(s, 1, N);
         system("pause");
        return 0;
     }

void matrix_chain_order(int *p, int len, int m[N + 1][N + 1], int s[N + 1][N + 1])
{
         int i, j, k, t;
         for (i = 0; i <= N; ++i)
                 m[i][i] = 0;
         for (t = 2; t <= N; t++)  //当前链乘矩阵的长度
             {
                 for (i = 1; i <= N - t + 1; i++)  //从第一矩阵开始算起,计算长度为t的最少代价
                     {
                        j = i + t - 1;//长度为t时候的最后一个元素
                         m[i][j] = MAXVALUE;  //初始化为最大代价
                     for (k = i; k <= j - 1; k++)   //寻找最优的k值,使得分成两部分k在i与j-1之间
                             {
                                 int temp = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];
                                 if (temp < m[i][j])
                                     {
                                         m[i][j] = temp;   //记录下当前的最小代价
                                        s[i][j] = k;      //记录当前的括号位置,即矩阵的编号
                                     }
                            }
                     }
             }
     }

//s中存放着括号当前的位置
 void print_optimal_parents(int s[N + 1][N + 1], int i, int j)
 {
         if (i == j)
                 cout << "A" << i;
        else
             {
                 cout << "(";
                 print_optimal_parents(s, i, s[i][j]);
                 print_optimal_parents(s, s[i][j] + 1, j);
                 cout << ")";
             }

         }
m value is:
0 15750 7875 9375 11875 15125
0 0 2625 4375 7125 10500
0 0 0 750 2500 5375
0 0 0 0 1000 3500
0 0 0 0 0 5000
0 0 0 0 0 0
s value is:
0 1 1 3 3 3
0 0 2 3 3 3
0 0 0 3 3 3
0 0 0 0 4 5
0 0 0 0 0 5
0 0 0 0 0 0
The result is:
((A1(A2A3))((A4A5)A6))请按任意键继续. . .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值