如何在memoization方法中打印值 - 动态pragraming

时间:2016-07-27 21:09:15

标签: algorithm matrix dynamic-programming memoization

我知道可以使用DP解决的问题,可以通过制表(自下而上)方法或记忆(自上而下)方法解决。个人我发现memoization是简单而有效的方法(分析只需要获得递归公式,一旦获得递归公式,蛮力递归方法可以很容易地转换为存储子问题的结果并重用它。)唯一的问题是我在这种方法中面临的是,我无法从我填写的表格中构建实际结果。

例如,在Matrix Product Parenthesization problem中(为了确定在矩阵上执行乘法的顺序以便乘法成本最小),我能够计算出不能在算法中生成顺序的最低成本。

例如,假设A是10×30矩阵,B是30×5矩阵,C是5×60矩阵。然后,

(AB)C = (10×30×5) + (10×5×60) = 1500 + 3000 = 4500 operations
A(BC) = (30×5×60) + (10×30×60) = 9000 + 18000 = 27000 operations.

在这里,我可以获得最低成本27000但无法获得A(BC)的订单。

我用过这个。假设F [i,j]表示乘以Ai所需的最小乘法次数..... Aj和给出的数组p [],其表示矩阵链,使得第i个矩阵Ai具有维度p [i-1] ] xp [i]。所以

                    0                 if i=j
     F[i,j]=
                   min(F[i,k] + F[k+1,j] +P_i-1 * P_k * P_j   where k∈[i,j)

以下是我创建的实现。

#include<stdio.h>
#include<limits.h>
#include<string.h>
#define MAX 4
int lookup[MAX][MAX];

int MatrixChainOrder(int p[], int i, int j)
{
    if(i==j) return 0;
    int min = INT_MAX;
    int k, count;

    if(lookup[i][j]==0){
        // recursively calculate count of multiplcations and return the minimum count
        for (k = i; k<j; k++) {
            int gmin=0;
            if(lookup[i][k]==0)
                lookup[i][k]=MatrixChainOrder(p, i, k);

            if(lookup[k+1][j]==0)
                lookup[k+1][j]=MatrixChainOrder(p, k+1, j);

            count = lookup[i][k] + lookup[k+1][j] + p[i-1]*p[k]*p[j];
            if (count < min){
                min = count;
              printf("\n****%d  ",k); // i think something has be done here to represent the correct answer ((AB)C)D  where first mat is represented by  A second by B and so on.
            }

        }
        lookup[i][j] = min;
    }

    return lookup[i][j];
}

// Driver program to test above function
int main()
{
    int arr[] = {2,3,6,4,5};
    int n = sizeof(arr)/sizeof(arr[0]);

    memset(lookup, 0, sizeof(lookup));
    int width =10;

    printf("Minimum number of multiplications is %d ", MatrixChainOrder(arr, 1, n-1));
    printf("\n  ---->");
    for(int l=0;l<MAX;++l)
    printf(" %*d ",width,l);
    printf("\n");
    for(int z=0;z<MAX;z++){
        printf("\n  %d--->",z);
    for(int x=0;x<MAX;x++)
    printf(" %*d ",width,lookup[z][x]);
    }

    return 0;
}

我知道使用制表方法打印解决方案很容易,但我想用记忆技术来做。


感谢。

1 个答案:

答案 0 :(得分:2)

您的代码正确计算了最小乘法数,但您正在努力展示最佳的矩阵乘法链。

有两种可能性:

  1. 计算表时,可以存储在另一个memoization数组中找到的最佳索引。
  2. 您可以从memoization数组中的结果重新计算最佳分割点。
  3. 第一个涉及在单独的数组中创建分割点:

    int lookup_splits[MAX][MAX];
    

    然后在MatrixChainOrder函数中更新它:

        ...
        if (count < min) {
            min = count;
            lookup_splits[i][j] = k;   
        }
    

    然后,您可以递归生成乘法链,如下所示:

    void print_mult_chain(int i, int j) {
        if (i == j) {
            putchar('A' + i - 1);
            return;
        }
        putchar('(');
        print_mult_chain(i, lookup_splits[i][j]);
        print_mult_chain(lookup_splits[i][j] + 1, j);
        putchar(')');
    }
    

    您可以使用print_mult_chain(1, n - 1)中的main来调用此功能。

    第二种可能性是你不缓存lookup_splits并根据需要重新计算它。

    int get_lookup_splits(int p[], int i, int j) {
        int best = INT_MAX;
        int k_best;
        for (int k = i; k < j; k++) {
            int count = lookup[i][k] + lookup[k+1][j] + p[i-1]*p[k]*p[j];
            if (count < best) {
                best = count;
                k_best = k;
            }
        }
        return k;
    }
    

    这与你在MatrixChainOrder中所做的计算基本相同,所以如果你使用这个解决方案,你应该适当地考虑代码以避免有两个副本。

    使用此功能,您可以调整上面的print_mult_chain使用它而不是lookup_splits数组。 (您需要传递p数组。)

    [此代码均未经过测试,因此您可能需要编辑修复错误的答案]。