用最少的变量实现矩阵链乘算法的构想及其递归输出结果c++代码

1.问题描述

给定n个矩阵构成的一个链,其中i=1,2,…n,矩阵A的维数为pi-1pi,对乘积 A1A2…An 以一种最小化标量乘法次数的方式进行加全部括号。
注意:在矩阵链乘问题中,实际上并没有把矩阵相乘,目的是确定一个具有最小代价的矩阵相乘顺序。找出这样一个结合顺序使得相乘的代价最低。

2.问题分析

  1. 最优加全部括号的结构
      动态规划第一步是寻找一个最优的子结构。假设现在要计算AiAi+1…Aj的值,计算Ai…j过程当中肯定会存在某个k值(i<=k   有分析可以到最优子结构为:假设AiAi+1…Aj的一个最优加全括号把乘积在Ak和Ak+1之间分开,则Ai…k和Ak+1…j也都是最优加全括号的。
  2. 一个递归解
      设m[i,j]为计算机矩阵Ai…j所需的标量乘法运算次数的最小值,对此计算A1…n的最小代价就是m[1,n]。现在需要来递归定义m[i,j],分两种情况进行讨论如下:
    当i==j时:m[i,j] = 0,(此时只包含一个矩阵)
    当i
  3. 计算最优代价
      虽然给出了递归解的过程,但是在实现的时候不采用递归实现,而是借助辅助空间,使用自底向上的表格进行实现。设矩阵Ai的维数为pi-1pi,i=1,2…n。输入序列为:p=,length[p] = n+1。使用m[n][n]保存m[i,j]的代价,s[n][n]保存计算m[i,j]时取得最优代价处k的值,最后可以用s中的记录构造一个最优解。书中给出了计算过程的伪代码,摘录如下:
  4. 构造一个最优解
      第三步中已经计算出来最小代价,并保存了相关的记录信息。因此只需对s表格进行递归调用展开既可以得到一个最优解。

3.编程分析

算法程序分为两部分,计算部分和递归输出部分

  • 计算部分
  1. 分析

假设需要计算 i 个矩阵 相乘,则任意两个矩阵之间都需要计算一次代价(自己到自己也需要计算,虽然一定为0),共需要1+2+3+…+i 次,存储到m矩阵(代价矩阵)是一个1到 i的阶梯型,举例当i=5时,m矩阵为

1 2 3 4 5
1 *
2 * *
3 * * *
4 * * * *
5 * * * * *

再来看s矩阵,s矩阵存储的是 i 矩阵乘到 j 矩阵时最优的分割处 k的取值,与m矩阵不同的是,任意两个矩阵之间都需要计算 k值但是自己到自己不需要计算,共需要1+2+3+…+(i-1)次,存储到s矩阵(k值矩阵)是一个1到 i-1的阶梯型,举例当i=5时,s矩阵为

1 2 3 4 5
1
2 *
3 * *
4 * * *
5 * * * *

可以发现s矩阵和m矩阵刚好可以放在同一个 i*i 的矩阵中,这样我们编程的时候就可以只定义一个 i*i 数组,将s矩阵存放在m矩阵对角的位置,循环变量我们准备使用一个矩阵位置 j 和要计算的另一个矩阵到 j 矩阵的距离 n ,减少资源的占用

  1. 代码

预编译部分,定义全局变量

#define Matrix_MUM 8
int min_s,min_k,M[Matrix_MUM][Matrix_MUM]={0},p[Matrix_MUM+1]={4,5,3,6,4,5,3,6,4};

main() 函数,n 是 i 到 j 相差的矩阵数,用到了 j 和 n 两个变量,i 可以通过 j 和 n 计算出来

int main()
{
int j,n;
	for(n=1;n<Matrix_MUM;n++)
		for(j=n;j<Matrix_MUM;j++)
			chain(j,j-n),M[j-n][j]=min_s,M[j][j-n]=min_k;
}

chain() 函数,计算k值

void chain(int j,int i)//计算
{
	int s,k;
	for(k=i;k<j;k++)
	{
		s=M[i][k]+M[k+1][j]+p[i]*p[k+1]*p[j+1];
		if(k==i)min_s=s,min_k=k;
		if(s<min_s)min_s=s,min_k=k;
	}
}
  • 输出部分
  1. 分析
    当 m矩阵和s矩阵计算完成后,我们就可以知道任意两个矩阵之间的最优计算方式,例如要找出 i 到 j 之间的最优计算方式,就需要在 s 矩阵中找出 i 到 j 的 k值作为分割点,将其分为两个部分,i 到 k 和k+1 到 j,之后继续在s矩阵分别中找到这两部分的分割点一直分割,直到 i 和 j 相等或者相邻(相差1)
    我们发现这像极了递归的手法,于是我们决定在程序最不重要的输出结果部分采用做作的递归方式,把上一步节省的资源充分利用起来
  2. 代码

*c() 函数,递归输出,当i和j相等或者相差1的时候结束,否则根据 k值分割继续递归

char *c(int i,int j)//结果

{
	char s[80],t[80];
	if(i==j)
	{
		s[0]='A';
		s[1]='0'+i;
		s[2]=0;
		return &s[0];
	}
	if(j-i==1)
	{
		s[0]='A';
		s[1]='0'+i;
		s[2]=0;
		t[0]='A';
		t[1]='0'+j;
		t[2]=0;
		return kh(s,t);
	}
	strcpy(s,c(i,M[j][i]));
	strcpy(t,c(M[j][i]+1,j));
	return kh(s,t);
}

kh() 函数,给字符串前后加上括号

char *kh(char *str1,char *str2)//括号
{
	char str[80]="(";
	strcat(str,str1);
	strcat(str,str2);
	strcat(str,")");
	return &str[0];
}

4.完整代码

#include
#include
#include
using namespace std;
#define Matrix_MUM 8
int min_s,min_k,M[Matrix_MUM][Matrix_MUM]={0},p[Matrix_MUM+1]={4,5,3,6,4,5,3,6,4};

int main()
{
	char s[80];
	char *c(int,int);
	void chain(int j,int i);
	void printmatrix();
	int j,n;//n:j-i ji之间相差几个矩阵
	for(n=1;n<Matrix_MUM;n++)
		for(j=n;j<Matrix_MUM;j++)//i=j-n
			chain(j,j-n),M[j-n][j]=min_s,M[j][j-n]=min_k;//s矩阵存在对称位置
		printmatrix();
		strcpy(s,c(0,6));
		puts(s);
		getchar();
		return 0;
}
void chain(int j,int i)//计算
{
	int s,k;
	for(k=i;k<j;k++)
	{
		s=M[i][k]+M[k+1][j]+p[i]*p[k+1]*p[j+1];
		if(k==i)min_s=s,min_k=k;
		if(s<min_s)min_s=s,min_k=k;
	}
}







void printmatrix()//输出
{
	int i,j;
	cout<<"输出m矩阵"<<endl;
	for(j=0;j<Matrix_MUM;j++)
	{
		for(i=0;i<=j;i++)
			cout<<M[i][j]<<"  ";
		cout<<endl;
	}
	cout<<endl<<"输出s矩阵";
	for(j=0;j<Matrix_MUM;j++)
	{
		for(i=0;i<=j-1;i++)
			cout<<M[j][i]+1<<"  ";
		cout<<endl;
	}
}
char *kh(char *str1,char *str2)//括号
{
	char str[80]="(";
	strcat(str,str1);
	strcat(str,str2);
	strcat(str,")");
	return &str[0];
}
char *c(int i,int j)//结果

{
	char s[80],t[80];
	if(i==j)
	{
		s[0]='A';
		s[1]='0'+i;
		s[2]=0;
		return &s[0];
	}
	if(j-i==1)
	{
		s[0]='A';
		s[1]='0'+i;
		s[2]=0;
		t[0]='A';
		t[1]='0'+j;
		t[2]=0;
		return kh(s,t);
	}
	strcpy(s,c(i,M[j][i]));
	strcpy(t,c(M[j][i]+1,j));
	return kh(s,t);
}

你可能感兴趣的:(算法,动态规划,矩阵)