[TOC]
7-1 矩阵链相乘问题 矩阵的乘法定义如下:设A 是m ×p 的矩阵,B 是p ×n 的矩阵,则A 与B 的乘积为m ×n 的矩阵,记作C =AB ,其中,矩阵C 中的第i 行第j 列元素cij 可以表示为:cij =Σk =1pa ik ×bkj =ai 1b 1j +ai 2b 2j +⋯+ai pb pj .
当多个矩阵相乘时,采用不同的计算顺序所需的乘法次数不相同。例如,A 是50×10的矩阵,B 是10×20的矩阵,C 是20×5的矩阵, 计算ABC 有两种方式:(AB )C 和A (BC ),前一种需要15000次乘法计算,后一种则只需3500次。
设A 1,A 2,…,An 为矩阵序列,Ai 是阶为Pi −1∗Pi 的矩阵(1≤i ≤n )。试确定矩阵的乘法顺序,使得计算A 1A 2…An 过程中元素相乘的总次数最少。
输入格式: 每个输入文件为一个测试用例,每个测试用例的第一行给出一个正整数n (1≤n ≤500),表示一共有n 个矩阵A 1,A 2,…,An ,第二行给出n +1个整数P 0,P 1…Pn ,以空格分隔,其中1≤Pi ≤100(0≤i ≤n ),第i 个矩阵Ai 是阶为Pi −1∗Pi 的矩阵。
输出格式: 获得上述矩阵的乘积,所需的最少乘法次数。
输入样例: 在这里给出一组输入。例如:
输出样例: 在这里给出相应的输出。例如:
算法步骤: 1.初始化一个二维数组m,大小为n*n;
2.对于i=1到n,设置m[i]_[i]=0,即对角线上的元素置零;
3.自底到上、自左到右对对角线右边的空位进行填表,计算m[i]_[j];
4.根据状态转移方程更新数组m;
5.最终m[1]_[n]即为最少数乘次数。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include<iostream> using namespace std; int n; int p[10000]; //因为可相乘矩阵要求RA=CB,所以p[i-1]代表矩阵行数,p[i]代表矩阵列数 int m[10000][10000];//数组m记录Ai···Aj所需的最少数乘次数 //int s[10000][10000];数组s用于记录最优断开位置 int MatrixChain(){ for(int i=1;i<=n;i++) m[i][i]=0;//对角线元素计为0,因为i=j时只有一个矩阵,无需乘法 for(int i=n;i>=1;i--){//自底而上填表 for(int j=i+1;j<=n;j++){ m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];//更新最小数乘次数 //s[i][j]=i;当前最优断点为i for(int k=i+1;k<j;k++){ //寻找最优次序中的断开位置,范围是i+1到j-1,因为这个断开位置既不会 是第一个矩阵也不会是最后一个矩阵 int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j]; //p[i-1]*p[k]*p[j]是Ai···Ak与Ak+1···Aj的数乘次数 if(t<m[i][j]){ m[i][j]=t;//如果当前值更优,更换m[i][j] //s[i][j]=k;更换最优断点 } } } } return m[1][n]; } int main(){ cin>>n; for(int i=0;i<n+1;i++){ cin>>p[i]; } int result=MatrixChain(); cout<<result; return 0; }
7-2 最大k乘积 设I是一个n位十进制整数。如果将I划分为k段,则可得到k个整数。这k个整数的乘积称为I的一个k乘积。试设计一个算法,对于给定的I和k,求出I的最大k乘积。
如3*12=26
31*2=62
此时最优解为62
输入格式: 第1 行中有2个正整数n和k。正整数n是序列的长度;正整数k是分割的段数。 接下来的一行中是一个n位十进制整数。(n<=10)
输出格式: 计算出的最大k乘积
输入样例1:
输出样例1:
输入样例2:
输出样例2:
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include<iostream> #include<cstring> #include<algorithm> using namespace std; int dp[15][15]; char numstr[15]; int num[15]; int getValue(int i,int j){ int sum = 0; for(int k = i;k < j;k++){ sum += num[k]; sum *= 10; } return sum + num[j]; } void dpAlgo(int l,int k){ for(int i = 1;i <= l;i++) dp[i][1] = getValue(1,i); for(int i = 0;i <= l;i++){ for(int j = 2;j <= k;j++){ int temp = 0; for(int d = 1;d < i;d++) temp = max(temp,dp[d][j - 1] * getValue(d + 1,i)); dp[i][j] = temp; } } } int main() { int l,k; cin >> l >> k >> numstr;//输入长度l、分割段数k、字符串序列 for(int i = 0;i < l;i++) num[i + 1] = numstr[i] - '0';//去掉空字符,将字符串转化成整数数组 dpAlgo(l,k); cout << dp[l][k]; return 0; }