动态规划特训:最优矩阵链乘(递归/递推解法)

问题描述:在线性代数里,我们都学过矩阵的乘法。矩阵的乘法不满足分配律,但是满足结合律,因此 (A x B)x C 与 A x(B x C)的运算结果是一样的,但是中间的运算量却可能不一样。

例如:假设A、B、C矩阵分别是 2 x 3、3 x 4、4 x 5 的,则 (A x B)x C   的运算量是 2 x 3 x 4 + 2 x 4 x 5 = 64,但是 A x(B x C)的运算量是 3 x 4 x 5 + 2 x 3 x 5 = 90。(想想运算量为什么是这么计算的。)显然第一种计算方法比较节省计算量。

好,现在考虑下面的问题:给出n个矩阵组成的序列,设计一种方法,把他们按照一定的顺序依次乘起来(你也可以理解为不断地加括号),是的总的计算量尽量小。假设第i个矩阵 Ai 是pi-1 X pi的。

解题思路:用dp[i][j]表示从i矩阵到j矩阵的最大链乘,然后考虑进行状态转移,因为链乘矩阵满足结合律,可以分解成i到k的链乘与k+1到j的链乘加上两组合矩阵链乘。即dp[i][j]=min{dp[i][k]+dp[k+1][j]+A[i].a*A[k].b*A[j].b}。利用记忆搜索法递归很容易能够求得最优解:

memset(d,-1,sizeof(d));
for(int i=1;i<=n;i++)
{
	d[i][i]=0;
}

int f(int i,int j)
{
	int &a=d[i][j];
	if(a!=-1) return a;
	a=inf;
	for(int k=i;k<j;k++)
	{
		a=min(a,f(i,k)+f(k+1,j)+A[i].a*A[k].b*A[j].b);
	}
	return a;
}

然而使用递推的解法则递推顺序需要考虑,如果直接定义i,j,k递增或递减枚举其实并不正确,因为这么一来相当于是推以i为起点,终点不断枚举,再枚举中间段,可是中间段此时未知。正确的递推方法是以遍历矩阵链乘的长度,定义len作为最外层循环,从2循环至n:

		for(int i=1;i<=n;i++)     //初始化 
		{
			for(int j=1;j<=n;j++)
			{
				dp[i][j]=inf;
			}
		}
		for(int i=1;i<=n;i++)  //边缘初始化 
		{
			dp[i][i]=0;
		}
		for(int len=2;len<=n;len++)     //以链乘长度作为最外层枚举 
		{
			for(int i=1;i+len-1<=n;i++)
			{
				int j=i+len-1;
				for(int k=i;k<j;k++)
				{
					dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+A[i].a*A[k].b*A[j].b);
				}
			}
		}

猜你喜欢

转载自blog.csdn.net/mavises/article/details/82112794
今日推荐