一、实验环境
操作系统:Windows 10 64位
内存:8GB
CPU:i5-5200U 2.20~2.20GHz
IDE:Code::Blocks 17.12
二、实验内容
1) 对于矩阵连乘问题,用递归程序穷举输出所有可能的加括号结果;
2) 对1)确定导致宕机的矩阵个数n的临界值;
3) 根据1)找出最优解,并把加括号的结果输出;
4) 对于矩阵连乘问题,用动态规划求最优解,并把加括号的结果输出;
三、代码实现
1) 版本1:用递归方法,穷举并对比找出最优解:
在main函数中的调用方法:
// 定义新类型typedef pair mul;
// 辅助函数bool Cmp(const mul m1, const mul m2);
vector combine(vector v1, vector v2, int left_d, int mid_d, int right_d);
vector allComb(int *dimensions, int left, int right);
void allPrint(vector allResult);
// 测试用的数据int n1 = 4, dimensions1[] = {50, 10, 40, 30, 5};
int n2 = 5, dimensions2[] = {50, 10, 40, 30, 5, 35};
int n3 = 6, dimensions3[] = {30, 35, 15, 5, 10, 20, 25};
int main()
{
int n = n1;
int *dimensions = dimensions1;
// 递归输出所有可能结果 vector allResult = allComb(dimensions, 1, n);
allPrint(allResult);
return 0;
}
allComb(找出所有加括号的结果)实现:
vector allComb(int *dimensions, int left, int right) {
vector comb;
if (left == right) comb.push_back(make_pair(to_string(left), 0));
vector sub1, sub2, temp;
for (int i = left; i < right; i++) {
sub1 = allComb(dimensions, left, i);
sub2 = allComb(dimensions, i + 1, right);
temp = combine(sub1, sub2, dimensions[left - 1], dimensions[i], dimensions[right]);
comb.insert(comb.begin(), temp.begin(), temp.end());
// allPrint(comb);
}
return comb;
}
辅助函数combine(用于整合子问题的结果)实现:
vector combine(vector v1, vector v2, int left_d, int mid_d, int right_d) {
vector result;
int s1 = v1.size(), s2 = v2.size(), temp_comp;
string temp;
for (int i = 0; i < s1; i++) {
for (int j = 0; j < s2; j++) {
temp = "(" + v1[i].first + v2[j].first + ")";
temp_comp = v1[i].second + v2[j].second + left_d * mid_d * right_d;
result.push_back(make_pair(temp, temp_comp));
}
}
return result;
}
辅助函数allPrint(用于输出所有加括号的结果以及最优解)实现:
void allPrint(vector allResult) {
sort(allResult.begin(), allResult.end(), Cmp);
int length = allResult.size();
cout << "Total: " << length << endl;
int prox = allResult[0].second, index = 0;
for (int i = 0; i < length; i++) {
if (allResult[i].second < prox) {
prox = allResult[i].second;
index = i;
}
cout << allResult[i].first << endl;
}
cout << endl << "Recursive method's result";
cout << endl << "The proximal solution costs "
<< prox << " times of multiplication. As shown below: " << endl;
cout << allResult[index].first << endl;
}
辅助函数Cmp(自定义排序方式)实现:
bool Cmp(const mul m1, const mul m2) {
return m1.first < m2.first;
}
2) 版本2:用动态规划找出最优解:
用到的辅助变量与函数如下:
// 动态规划求解
const int Max = 100;
int complexity[Max][Max], prox[Max][Max];
void proxComb(int *dimensions, int n, int complexity[][Max], int prox[][Max]);
void proxPrint(int n, int complexity[][Max], int prox[][Max]);
string proxString(int prox[][Max], int left, int right);
proxComb(找出最优的加括号结果)实现:
void proxComb(int *dimensions, int n, int complexity[][Max], int prox[][Max]) {
// complexity为记录乘法次数的矩阵,只用到上三角区域
// 对角线上的元素表示单个矩阵,故而乘法次数为0
for (int i = 1; i <= n; i++) complexity[i][i] = 0;
// 外循环为列,内循环从下往上更新complexity
for (int i = 2; i <= n; i++) {
for (int j = i - 1; j > 0; j--) {
// 初始化为从左数第一项
complexity[j][i] = 0 + complexity[j + 1][i] +
dimensions[j - 1] * dimensions[j] * dimensions[i];
prox[j][i] = j;
// 从左往右寻找更优的组合(如果有)
for (int k = j + 1; k < i; k++) {
int temp = complexity[j][k] + complexity[k + 1][i] +
dimensions[j - 1] * dimensions[k] * dimensions[i];
if (temp < complexity[j][i]) {
complexity[j][i] = temp;
prox[j][i] = k;
}
}
}
}
}
辅助函数proxPrint(用于输出最优解)实现:
void proxPrint(int n, int complexity[][Max], int prox[][Max]) {
string result = proxString(prox, 1, n);
cout << endl << "Dynamic programming's result";
cout << endl << "The proximal solution costs "
<< complexity[1][n] << " times of multiplication. As shown below: " << endl;
cout << result << endl;
}
辅助函数proxString(递归输出最优解的字符串)实现:
string proxString(int prox[][Max], int left, int right) {
if (left == right) {
return to_string(left);
}
int prox_point = prox[left][right];
string sub1 = proxString(prox, left, prox_point);
string sub2 = proxString(prox, prox_point + 1, right);
return "(" + sub1 + sub2 + ")";
}
四、代码测试/实验结果
1) 版本1:
n = 4时:
n = 6时:(部分截图)
n = 15时:(将输出结果的代码注释掉、以及不传入实际矩阵大小,只考虑矩阵个数)
而到了n = 20时,内存占用大致为85%~95%,应该是可以算出结果来的。但是等了45分钟后还没出结果,所以强制退出了。
而根据问题规模随n的增长速度来看,估计21~25的时候在本机配置下就会成功死机了。。。
2) 版本2:作为比较,使用两个版本的结果相互检验
n = 4时:
n = 6时:
The END.