ACM基础之动态规划DP:矩阵链乘法Matrix-chain multiplication

文章目录

  • Reference


ACM基础之动态规划DP:矩阵链乘法Matrix-chain multiplication_第1张图片
ACM基础之动态规划DP:矩阵链乘法Matrix-chain multiplication_第2张图片
ACM基础之动态规划DP:矩阵链乘法Matrix-chain multiplication_第3张图片
Instead, use a dynamic program to fill in a table m[i,j]:

  • Start by setting m[i,i]=0 for i = 1,…,n.
  • Then compute m[1,2], m[2,3],…,m[n-1,n].
  • Then m[1,3], m[2,4],…,m[n-2,n],…
  • … so on till we can compute m[1,n].

ACM基础之动态规划DP:矩阵链乘法Matrix-chain multiplication_第4张图片

// p比如<30,35,15>,表示A1(30*35)和A2(35*15)
MATRIX-CHAIN-ORDER(p):
	// p用n+1个数表示n个矩阵相乘
	n ← length[p] - 1
	// 对表中第一条对角线初始化当i=j的情况
	for i ← 1 to n:
		do	m[i, i]0
	// 控制每条红色对角线的行号区间递减,每条红色对角线列号在随行号递增的同时随对角线向上加一个数递增
	for l ← 2 to n:
			// 每条红色对角线的行号区间,[1,n-1],[1,n-2],...,[1,1]
		do	for i ← 1 to n - l + 1:
					// 每条红色对角线的每行对应的列号
				do	j ← i + l - 1
					// 先初始化正无穷
					m[i, j] ← ∞
					// 遍历k,i≤k
					for k ← i to j - 1:
							// 公式
						do	q ← m[i, k] + m[k + 1, j] + (pi-1)(pk)(pj)
							// 比较新试的k和原来哪个更小
							if	q < m[i, j]
							then	m[i, j] ← q
									s[i, j] ← k 	

ACM基础之动态规划DP:矩阵链乘法Matrix-chain multiplication_第5张图片

  • m [ 1 , 2 ] = m [ 1 , 1 ] + m [ 2 , 2 ] + p 0 p 1 p 2 = 0 + 0 + ( A 1 ) ( A 2 ) = 30 × 35 × 15 = 15750 m[1,2]=m[1,1]+m[2,2]+p_0p_1p_2=0+0+(A_1)(A_2)=30\times35\times15=15750 m[1,2]=m[1,1]+m[2,2]+p0p1p2=0+0+(A1)(A2)=30×35×15=15750
  • m [ 1 , 3 ] m[1,3] m[1,3]
    • k=1时: m [ 1 , 3 ] = m [ 1 , 1 ] + m [ 2 , 3 ] + p 0 p 1 p 3 = 0 + 2625 + ( A 1 ) ( A 2 A 3 ) = 2625 + 30 × 35 × 5 = 7875 m[1,3]=m[1,1]+m[2,3]+p_0p_1p_3=0+2625+(A_1)(A_2A_3)=2625+30\times35\times5=7875 m[1,3]=m[1,1]+m[2,3]+p0p1p3=0+2625+(A1)(A2A3)=2625+30×35×5=7875
    • k=2时: m [ 1 , 3 ] = m [ 1 , 2 ] + m [ 3 , 3 ] + p 0 p 2 p 3 = 15750 + 0 + ( A 1 A 2 ) ( A 3 ) = 15750 + 30 × 15 × 5 = 18000 m[1,3]=m[1,2]+m[3,3]+p_0p_2p_3=15750+0+(A_1A_2)(A_3)=15750+30\times15\times5=18000 m[1,3]=m[1,2]+m[3,3]+p0p2p3=15750+0+(A1A2)(A3)=15750+30×15×5=18000
#include 
#include 
using namespace std;

#define INF 0x3f3f3f3f

void matrix_chain_order(vector<int> &p, vector<vector<int>> &m, vector<vector<int>> &s)
{
    // p用n+1个数表示n个矩阵相乘
    int n = p.size() - 1;
    // 对表中第一条对角线初始化当i=j的情况
    // 表行列总数都是n个矩阵个,[1,n]
    for (int i = 1; i <= n; i++)
    {
        m[i][i] = 0;
    }
    // 控制每条红色对角线的行号区间递减,每条红色对角线列号在随行号递增的同时随对角线向上加一个数递增
    for (int l = 2; l <= n; l++)
    {
        // 每条红色对角线的行号区间,[1,n-1],[1,n-2],...,[1,1]
        for (int i = 1; i <= n - l + 1; i++)
        {
            // 每条红色对角线的每行对应的列号
            int j = i + l - 1;
            // 先初始化正无穷
            m[i][j] = INF;
            // 遍历k,i≤k
            for (int k = i; k <= j - 1; k++)
            {
                // 公式,表示新试k的代价
                int q = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];
                // 比较新试的k和原来哪个更小
                if (q < m[i][j])
                {
                    m[i][j] = q;
                    s[i][j] = k;
                }
            }
        }
    }
}

// void print_optimal_parens(vector> &s, int i, int j)
// {
//     if (i == j)
//     {
//         printf("A%d\n", i);
//     }
//     else
//     {
//         printf("(");
//         print_optimal_parens(s, i, s[i, j]);
//         print_optimal_parens(s, s[i, j] + 1, j);
//         printf(")\n");
//     }
// }

int main(void)
{
    // 矩阵链,7个数表示6个矩阵
    vector<int> p{30, 35, 15, 5, 10, 20, 25};

    // 这里我们不从0开始,从1开始使用,[1,6]范围
    // m,表示记录结果
    vector<vector<int>> m(p.size(), vector<int>(p.size()));
    // s,表示选择的k
    vector<vector<int>> s(p.size(), vector<int>(p.size()));

    // 调用
    matrix_chain_order(p, m, s);

    // 输出m
    for (int i = 1; i < p.size(); i++)
    {
        for (int j = 1; j < p.size(); j++)
        {
            printf("%5d ", m[i][j]);
        }
        printf("\n");
    }
    printf("\n");

    // 输出s
    for (int i = 1; i < p.size(); i++)
    {
        for (int j = 1; j < p.size(); j++)
        {
            printf("%5d ", s[i][j]);
        }
        printf("\n");
    }
    return 0;
}

Reference

(最大矩阵链乘)Matrix-chain product

你可能感兴趣的:(#,ACM基础)