我知道可以使用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;
}
我知道使用制表方法打印解决方案很容易,但我想用记忆技术来做。
感谢。
答案 0 :(得分:2)
您的代码正确计算了最小乘法数,但您正在努力展示最佳的矩阵乘法链。
有两种可能性:
第一个涉及在单独的数组中创建分割点:
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
数组。)
[此代码均未经过测试,因此您可能需要编辑修复错误的答案]。