矩阵连乘问题是动态规划的重要例子,弄了一个晚上加一个小时终于AC了。。。。感觉自己很拙。。。。。
矩阵链乘问题
输入:
共两行
第一行 N ( 1<=N<=100 ),代表矩阵个数。
第二行有 N+1 个数,分别为 A1 、 A2 …… An+1 ( 1<=Ak<=10 ), Ak 和 Ak+1 代表第 k 个矩阵是个 Ak X Ak+1 形的。
输出:
共两行
第一行 M ,为最优代价。注:测试用例中 M 值保证小于 2^31
第二行为最优顺序。如 (A1((A2A3)A4)) ,最外层也加括号。
注意:测试用例已经保证了输出结果唯一,所以没有AAA的情况.
解:
算法其实不难,就是填表,注意填表时的顺序,应该是斜线填充,一次填一根斜线。
动态规划递归方程的建立:
子问题状态的建模(很关键):令m[i][j]表示第i个矩阵至第j个矩阵这段的最优解。
显然如果i=j,则m[i][j]这段中就一个矩阵,需要计算的次数为0;
如果i>j,则m[i][j]=min{m[i][k]+m[k+1][j]+p[i-1]Xp[k]Xp[j]},其中k,在i与j之间游荡,所以i<=k<j ;
这一段算法不难,问题是输出。弄了好久想了好几种方法都没成功。
书上的算法貌似不对,递归倒是用的递归,但是书上的递归输出有问题。。。。好罗嗦
正确的输出代码应该是这样的:
void print(int i, int n, int point[][101])
{
if(i == n) {printf("A%d", i);}
else if(i+1 == n) printf("(A%dA%d)", i, n);
else {
printf("(");
print(i, point[i][n], point);
print(point[i][n]+1, n,point);
printf(")");
}
}
整体代码如下,仅供参考:
#include"stdafx.h"
#include"stdio.h"
#include<stdlib.h>
#define MAX 101
void print(int i, int n, int point[][101])
{
if(i == n) {printf("A%d", i);}
else if(i+1 == n) printf("(A%dA%d)", i, n);
else {
printf("(");
print(i, point[i][n], point);
print(point[i][n]+1, n,point);
printf(")");
}
}
int main()
{
int n, i, j, k, t, temp_value, a[MAX], point[MAX][MAX], times[MAX][MAX];
//long int ans;
scanf("%d", &n);
for(i = 0; i <= n; i++)
scanf("%d", &a[i]);
for(i = 1; i <= n; i++) {times[i][i] = 0;}
for(k = 2; k <= n; k++) { //斜线方向
for(i = 1; i <= n - k + 1; i++) { //斜下
j = k +i - 1;//
times[i][j] = times[i+1][j] + a[i-1] * a[i] * a[j];//从j-1得到
point[i][j] = i;
for(t = i+1; t < j; t++) {
temp_value = times[i][t] + times[t+1][j] + a[i-1]*a[t]*a[j];
if(times[i][j] > temp_value) {
times[i][j] = temp_value;
point[i][j] = t;
}//if
}//for t
}//for i
}//for k
//输出顺序
printf("%d\n", times[1][n]);
if(n == 1) printf("(A1)\n");
else {
print(1, n, point);
printf("\n");
}
system("pause");
return 0;
}//main
转载于:https://www.cnblogs.com/kiwi/archive/2012/03/22/2411046.html