例如说,有四个矩阵ABCD相乘,那么所有的完全加括号结果为(A((BC)D)) (A(B(CD))) ((AB)(CD)) (((AB)C)D) (A(BC))D)。要求输出n个矩阵连乘所有的完全加括号结果。
解决方法一
- 基本思想:首先从1,2,3,4个矩阵的角度来归纳。如果只有一个矩阵A,那么很明显所有的完全加括号结果就是A本身。如果有两个矩阵A,B相乘,很明显所有的完全加括号结果就是AB。如果有三个矩阵A,B,C相乘,那么我们将考虑将矩阵链断开,分为两个子矩阵链,然后分别求取两个子矩阵链的所有完全加括号结果的集合,最后再求出这两个集合的笛卡儿积即可。此时三个矩阵共有两种断开方式:A,BC和AB,C。第一种断开方式中,左子矩阵链为A,该子矩阵链的所有完全加括号结果的集合已知为{A},右子矩阵链为BC,该子矩阵链的所有完全加括号结果的集合已知为{BC}。那么该断开方式的完全加括号结果为A(BC)。由此类推另外一种断开方式的完全加括号结果为(AB)C。所以,三个矩阵相乘的所有完全加括号结果为{A(BC),(AB)C}。如果有四个矩阵A,B,C,D相乘,断开方式有:A,BCD和AB,CD和ABC,D。第一种断开方式中,左子矩阵链为A,该子矩阵链的所有完全加括号结果的集合已知为{A},右子矩阵链为BCD,从前面分析可知其所有完全加括号结果为{B(CD),(BC)D},该断开方式的所有完全加括号结果为:A(B(CD))和A((BC)D),以此类推下去,我们可以发现n个矩阵划分的子矩阵链均可以在1~n-1个矩阵中找到对应的矩阵链。因此,要求出n个矩阵相乘的所有完全加括号结果,可以先从1个矩阵入手,求出这n个矩阵每一个矩阵的所有完全加括号结果并储存起来,再计算这n个矩阵每两个相邻矩阵的所有完全加括号结果并储存起来,再计算这n个矩阵每三个相邻矩阵的所有完全加括号结果并储存起来,以此类推,最后计算出这n个矩阵每n个相邻矩阵的所有完全加括号结果即n个矩阵相乘的所有完全加括号结果。
- 基本过程:假设矩阵链为A_1 A_2… A_n,
i.求出矩阵链每一个矩阵的所有完全加括号结果:A_1:{ A_1},A_2:{ A_2}
,…,A_n:{ A_n}
ii.求出矩阵链每两个矩阵的所有完全加括号结果:A_1 A_2:{ A_1 A_2},A_2 A_3:{ A_2 A_3},…,A_(n-1) A_n:{ A_(n-1) A_n}
iii.求出矩阵链每三个矩阵的所有完全加括号结果:A_1 A_2 A_3: { A_1 (A_2 A_3),(A_1 A_2)A_3},A_2 A_3 A_4: { A_2 (A_3 A_4), (A_2 A_3)A_4},…,A_(n-2) A_(n-1) A_n: { A_(n-1) (A_(n-1) A_n), (A_(n-2) A_(n-1))A_n}
…
…
…
最后得到矩阵链的所有完全加括号结果。里面有一些细节值得注意,就是如何找到特定矩阵链的所有完全加括号结果?在这里我用了unordered_map容器,将特定的矩阵链作为键值,将该矩阵链的所有完全加括号结果集合作为映射值,这样就能在较短时间内找到想要的结果。 - 代码
#include<iostream>
#include<vector>
#include<string>
#include<unordered_map>
#include<ctime>
using namespace std;
clock_t start,end_t;
int main()
{
cout << "输入矩阵相乘的个数:";
int n;
cin >> n;
cout << n <<"个元素的矩阵序列如下:";
string str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", str2 = str1.substr(0, n);
cout << str2<< endl;
cout << n << "个矩阵相乘的所有完全加括号结果:" << endl;
start = clock();
if (n == 1)
cout << "A" << endl;
else if (n == 2)
cout << "AB" << endl;
else if (n == 3)
cout << "(AB)C\nA(BC)" << endl;
else
{
unordered_map<string, vector<string>> record;
for (int i = 0; i < n; i++)
{
string t1(1,str2[i]);
record[t1] = {t1}; //保存一个矩阵的所有完全加括号结果
}
for (int i = 0; i < n-1; i++)
{
string t2(2, 'x');
t2[0] = str2[i];
t2[1] = str2[i + 1];
record[str2.substr(i, 2)] = {t2}; //保存每两个相邻矩阵的所有完全加括号结果
}
for(int t = n -2; t >= 1; t--)
{
for (int i = 0; i < t; i++)
{
string t3 = str2.substr(i, n - t + 1); //取出矩阵链每n-t-1个相邻矩阵(3-n)
for (int j = 1; j < n - t + 1; j++)
{
string t4 = t3.substr(0, j); //断开
string t5 = t3.substr(j, n - t - j + 1);
int count1 = record[t4].size(), count2 = record[t5].size();
for (int k1 = 0; k1 < count1; k1++) //求出两个集合的笛卡儿积
{
for (int k2 = 0; k2 < count2; k2++)
{
string t6;
if (record[t4][k1].size() == 1)
t6 += record[t4][k1];
else
t6 += "(" + record[t4][k1]+")";
if (record[t5][k2].size() == 1)
t6 += record[t5][k2];
else
t6 += "(" + record[t5][k2] + ")";
record[t3].push_back(t6);
}
}
}
}
//t--;
}
end_t = clock();
double endtime = (double)(end_t-start)/CLOCKS_PER_SEC;
cout << "Total time:" << endtime << endl;
system("pause");
vector<string>res = record[str2];
for (string i : res)
cout << i << endl;
cout << "一共有" << res.size() << "种可能的输出." << endl;
}
return 0;
}
解决方法二
1.基本思想:如果题目的要求是输出有多少种矩阵连乘的完全加括号的形式,那么有以下实现方法:
//n表示矩阵链的矩阵数目
int f(int n)
{
int num=0;
if (n == 1)
num = 1;
else
for (int i = 1; i != n; i++)
num += f(i)*f(n - i); //左子矩阵链完全加括号的数目乘以右子矩阵链完全加括号的数目
return num;
}
那么我们也可以考虑用这种方式来进行输出。
- 若n=1,那么直接输出A(假设该矩阵为A)
- 若n=2,那么直接输出(AB)(j假设该矩阵链为AB)
- 若n>2,那么可以将矩阵链分为左子矩阵链和右子矩阵链,然后分别求左子矩阵链的所有完全加括号结果和右子矩阵链的所有完全加括号结果,最后再求他们的笛卡儿积。
2.代码
#include<iostream>
#include<vector>
#include<string>
using namespace std;
vector<string> matrix_chain(string * p, int start, int length)
{
vector<string> ret;
if (length == 1) {
ret.push_back(p[start]);
}
else if (length == 2) {
ret.push_back("(" + p[start] + p[start + 1] + ")");
}
else {
for (int i = 1; i != length; i++) {
vector<string> part1 = matrix_chain(p, start, i);
vector<string> part2 = matrix_chain(p, start + i, length - i);
for (int k = 0; k != part1.size(); k++) {
for (int m = 0; m != part2.size(); m++) {
ret.push_back("(" + part1[k] + part2[m] + ")");
}
}
}
}
return ret;
}
int main()
{
int n;
cout << "请输入矩阵个数:";
cin >> n;
string* p = new string[n]; // 向量p用来存储n个矩阵
for(int i=0; i!=n; i++)
{
p[i] = char(i + char('A'));
}
vector<string> result = matrix_chain(p, 0, n);
cout << "理论上,方案数量:" << f(n) << endl;
cout << "矩阵链乘完全括号化方案数量:"<<result.size() << endl;
for (int i = 0; i != result.size(); i++)
cout << result[i] << endl;
return 0;
}