矩阵连乘问题 C语言实现
2015-11-12 22:22
232 查看
矩阵连乘问题.
eg.A1 A2 A3 A4 A5 A6, 已知:各矩阵的维数:A1=30*35,A2=35*15,A3=15*5,A4=5*10,A5=10*20, 则 int p[]={30,35,15,5,10,20,25};
A5=20*25 .隐含的条件是:两矩阵必须是相邻两个才能乘.求六个矩阵求其加括号的位置,从而使得连乘的次数最少.
解:思想:矩阵连乘用动态规划发求解的两个原因:
1.矩阵连乘问题的最优解包含着其中子问题的最优解.
2.在计算最优值的过程中,许多子问题被重复计算.
用A[i,j]来表示[Ai..Aj]加括号的位置.则有A[1,1]表示的给一个数组加括号的位置,0,同理也有A[I,I]=0;
假设我们将A[i,i+1...k,k+1,..,j]中间k的位置加括号,则有乘法的次数为:
A[I,I+1,...K]的乘法次数 + A[K+1,...J]乘法次数 + A[I,I+1...]*A[K+1...J]的次数
1.首先数组P={30,35,15,5,10,20,25},下表从0开始,6结束.
2.用二维数组m[i][j]表示最少乘法次数,s[i][j]表示当m[i][j]为最小时加括号的位置.
下面代码
//用来得到最优解的m[][] ,s[][];
void MatrixChain(int p[6] ,int n, int m[][7] ,int s[][7]){
int r = 0; //当前参与矩阵连乘的元素的个数
int i = 0; //记录其实下标
int j = 0; //记录终止下标
int k = 0; //表示当前还有的加括号
int t = 0; //交换
for(i = 1; i <= n; i++)
m[i][i] = 0; //当只有一个矩阵时,乘法次数是0
for(r = 2; r <= n; r++ ) //至少是两个矩阵参与连乘,最多有n个
for(i = 1; i <= n-r+1; i++){ //i<n-r+1,表示当R=3时,第一下标最多是4,才能组成(A4 A5 A6)保证其是三个.
j = i + r -1; //当起始下标和个数确定之后,终止下标是固定的
m[i][j] = m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j]; //都默认从起始下标之后加第一个括号,即当作从第一个断开得到初始值
s[i][j] = i;
for(k = i+1; k < j; k++){ //从第二层循环开始,也就是当r>2时,还会有j-i种加括号的方法
t = m[i][k] + m[k+1][j] + p[i-1]* p[k] *p[j];
if(t < m[i][j]){ //如果这j-i中方法里还有比第一种方法小的,就交换.
m[i][j] = t;
s[i][j] = k ;
}
}
}
}
void TrackBack(int i ,int j, int s[][7]){ //从i=1,j=6开始.
if(i==j) return ;
TrackBack(i,s[i][j],s); //递归的看第一个断开位置之前的
TrackBack(s[i][j]+1,j,s); //第一次断开位置之后的.
printf("A%d",i);
printf(" and A%d",j);
printf("\n");
}
int main(){
int n = 6;
int p[]={30,35,15,5,10,20,25}; //p用来存放每一个矩阵的行数
int s[7][7] = {0};
int m[7][7] = {0};
MatrixChain(p,n,m,s);
TrackBack(1,n,s);
}
eg.A1 A2 A3 A4 A5 A6, 已知:各矩阵的维数:A1=30*35,A2=35*15,A3=15*5,A4=5*10,A5=10*20, 则 int p[]={30,35,15,5,10,20,25};
A5=20*25 .隐含的条件是:两矩阵必须是相邻两个才能乘.求六个矩阵求其加括号的位置,从而使得连乘的次数最少.
解:思想:矩阵连乘用动态规划发求解的两个原因:
1.矩阵连乘问题的最优解包含着其中子问题的最优解.
2.在计算最优值的过程中,许多子问题被重复计算.
用A[i,j]来表示[Ai..Aj]加括号的位置.则有A[1,1]表示的给一个数组加括号的位置,0,同理也有A[I,I]=0;
假设我们将A[i,i+1...k,k+1,..,j]中间k的位置加括号,则有乘法的次数为:
A[I,I+1,...K]的乘法次数 + A[K+1,...J]乘法次数 + A[I,I+1...]*A[K+1...J]的次数
1.首先数组P={30,35,15,5,10,20,25},下表从0开始,6结束.
2.用二维数组m[i][j]表示最少乘法次数,s[i][j]表示当m[i][j]为最小时加括号的位置.
下面代码
//用来得到最优解的m[][] ,s[][];
void MatrixChain(int p[6] ,int n, int m[][7] ,int s[][7]){
int r = 0; //当前参与矩阵连乘的元素的个数
int i = 0; //记录其实下标
int j = 0; //记录终止下标
int k = 0; //表示当前还有的加括号
int t = 0; //交换
for(i = 1; i <= n; i++)
m[i][i] = 0; //当只有一个矩阵时,乘法次数是0
for(r = 2; r <= n; r++ ) //至少是两个矩阵参与连乘,最多有n个
for(i = 1; i <= n-r+1; i++){ //i<n-r+1,表示当R=3时,第一下标最多是4,才能组成(A4 A5 A6)保证其是三个.
j = i + r -1; //当起始下标和个数确定之后,终止下标是固定的
m[i][j] = m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j]; //都默认从起始下标之后加第一个括号,即当作从第一个断开得到初始值
s[i][j] = i;
for(k = i+1; k < j; k++){ //从第二层循环开始,也就是当r>2时,还会有j-i种加括号的方法
t = m[i][k] + m[k+1][j] + p[i-1]* p[k] *p[j];
if(t < m[i][j]){ //如果这j-i中方法里还有比第一种方法小的,就交换.
m[i][j] = t;
s[i][j] = k ;
}
}
}
}
void TrackBack(int i ,int j, int s[][7]){ //从i=1,j=6开始.
if(i==j) return ;
TrackBack(i,s[i][j],s); //递归的看第一个断开位置之前的
TrackBack(s[i][j]+1,j,s); //第一次断开位置之后的.
printf("A%d",i);
printf(" and A%d",j);
printf("\n");
}
int main(){
int n = 6;
int p[]={30,35,15,5,10,20,25}; //p用来存放每一个矩阵的行数
int s[7][7] = {0};
int m[7][7] = {0};
MatrixChain(p,n,m,s);
TrackBack(1,n,s);
}
相关文章推荐
- xcode快捷键
- 观察者模式
- nyoj--1036--非洲小孩(区间相交问题)
- 如何创建xp虚拟机
- linux test命令使用
- 如何在Ubuntu/Linux中使用LiveReload+Sublime Text 3
- 三级缓存(内存、本地、网络)
- 寄存器
- 数论总结 - by yzq986
- 第26讲 项目三-分段函数求值switch语句版
- Error While Loading Shared Libraries, Cannot Open Shared Object File
- 有点小烦躁
- ACM训练方法
- REST接口
- 经典排序算法分析
- 第一节 个人博客搭建概览
- [kuangbin带你飞]专题一 简单搜索 J - Fire! UVA 11624
- c++ 引用和指针的区别
- 死锁(一)
- 核心java系列——接口和抽象类