分治法解决矩阵乘法问题
传统for循环:
#include<iostream>
#include<cstdio>
#include <vector>
#include<algorithm>
using namespace std;
int n, m, p;
int main()
{
printf("第一个n×m矩阵?\n");
cin >> n >> m;
vector<vector<int>> A(n, vector<int>(m));
printf("依次输入A矩阵元素:\n");
//读入矩阵A
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> A[i][j];
printf("A矩阵如下:\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
cout << A[i][j] << " ";
cout << endl;
}
cout << endl;
//读入矩阵B
printf("B矩阵有几列:\n");
cin >> p;
vector<vector<int>> B(m, vector<int>(p));
printf("依次输入B矩阵元素:\n");
for (int i = 0; i < n; i++)
for (int j = 0; j < p; j++)
cin >> B[i][j];
printf("A矩阵如下:\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < p; j++)
cout << B[i][j] << " ";
cout << endl;
}
cout << endl;
printf("矩阵相乘得到:\n");
//三重循环运算输出结果
for (int i = 0; i < n; i++)
{
for (int j = 0; j < p; j++)
{
int res = 0;
for (int k = 0; k < m; k++)
{
res += A[i][k] * B[k][j];
}
cout << res << " ";
}
cout << endl;
}
return 0;
}
分治法:
咱就是说,暴力循环解法确实好理解,但是考虑到当两个矩阵的维度变得很大的时候时间复杂度也是个需要解决的问题。
所以咱考虑使用一种更优的解法。
通常我们在进行数据处理的时候,会将比较大的数据分割成一个个小数据。那么给到两个很大的矩阵,也可以考虑分治的方法逐步解决处理一个个小矩阵。我们发现,两个矩阵相乘时,有8次的乘法运算,4次的加法运算。
矩阵乘法的复杂度主要体现在相乘上,而加法的次数增加几次在复杂度上是几乎不会上升多少。所以我们可以通过减少乘法的运算次数,从而进一步降低算法的复杂度。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 4;
int A[N][N], B[N][N], C[N][N];
产生n个随机数组从1~10中选
void random(int a[][N]) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
a[i][j] = rand() % 10 + 1;
}
}
}
//矩阵输出函数
void output(int a[][N]) {
int count = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
cout << a[i][j] << "\t";
}
cout << endl;
}
}
// 二阶矩阵用通常的算法来做,做为递归终止的条件
void end(int A[][N], int B[][N], int C[][N])
{
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
{
C[i][j] = 0; // 恢复现场
for (int k = 0; k < 2; k++)
C[i][j] = C[i][j] + A[i][k] * B[k][j];
}
}
// 矩阵相加
void add(int n, int A[][N], int B[][N], int C[][N])
{
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
C[i][j] = A[i][j] + B[i][j];
}
//矩阵乘法算法
void strassen(int n, int A[][N], int B[][N], int C[][N])
{
int A11[N][N], A12[N][N], A21[N][N], A22[N][N];
int B11[N][N], B12[N][N], B21[N][N], B22[N][N];
int C11[N][N], C12[N][N], C21[N][N], C22[N][N];
int M1[N][N], M2[N][N], M3[N][N], M4[N][N], M5[N][N], M6[N][N], M7[N][N], M8[N][N];
//设置边界条件:当矩阵阶数为2时 递归终止
if (n == 2)
{
end(A, B, C); // 二阶
}
else
{
// 将矩阵拆为4块
for (int i = 0; i < n / 2; i++)
for (int j = 0; j < n / 2; j++)
{
A11[i][j] = A[i][j];
A12[i][j] = A[i][j + n / 2];
A21[i][j] = A[i + n / 2][j];
A22[i][j] = A[i + n / 2][j + n / 2];
B11[i][j] = B[i][j];
B12[i][j] = B[i][j + n / 2];
B21[i][j] = B[i + n / 2][j];
B22[i][j] = B[i + n / 2][j + n / 2];
}
strassen(n / 2, A11, B11, M1);
strassen(n / 2, A12, B21, M2);
strassen(n / 2, A11, B12, M3);
strassen(n / 2, A12, B22, M4);
strassen(n / 2, A21, B11, M5);
strassen(n / 2, A22, B21, M6);
strassen(n / 2, A21, B12, M7);
strassen(n / 2, A22, B22, M8);
//递归结束并将数值返回数组C
add(N / 2, M1, M2, C11);
add(N / 2, M3, M4, C12);
add(N / 2, M5, M6, C21);
add(N / 2, M7, M8, C22);
//求得矩阵C
for (int i = 0; i < n / 2; i++)
for (int j = 0; j < n / 2; j++)
{
C[i][j] = C11[i][j];
C[i][j + n / 2] = C12[i][j];
C[i + n / 2][j] = C21[i][j];
C[i + n / 2][j + n / 2] = C22[i][j];
}
}
}
int main()
{
clock_t start, finish; //定义一个计数器
double timee; //用于存储时间单位
//初始化矩阵A和矩阵B
random(B);
cout << "随机生成矩阵A" << endl;
random(A);
output(A);
cout << "随机生成矩阵B" << endl;
random(B);
output(B);
start = clock();//开始计时
cout << "矩阵A和B的乘积为:" << endl;
strassen(N, A, B, C);
output(C);
finish = clock();
timee = finish;
cout << "此算法运行时间单位:" << timee << endl;
return 0;
}