分治法解决矩阵乘法问题

分治法解决矩阵乘法问题

传统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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AKA山风点火

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值