分治法经典问题:Strassen矩阵乘法

引入

  参考文献https://www.geeksforgeeks.org/strassens-matrix-multiplication/
  目标:给定两个形状为 n n n的方阵 A A A B B B,求解它们的矩阵相乘结果

1 朴素方法

  就是两个矩阵相乘咯:

#include <iostream>

/*
 * 常规方阵乘法
 * :param	X: 方阵1
 * :param	Y: 方阵2
 * :retutn  矩阵相乘结果
 */
int** matrix_multiply(int** X, int** Y, int n);

/*
 * 展示方阵
 * :param   X: 待展示方阵
 * :param   n: 方阵大小
 */
void matrix_show(int** X, int n);

int main()
{
	// 方阵初始化
	int**X = new int* [2], **Y = new int*[2];
	for (int i = 0; i < 2; i++)
	{
		X[i] = new int[2];
		Y[i] = new int[2];
		for (int j = 0; j < 2; j++)
		{
			X[i][j] = i + j;
			Y[i][j] = i - j;
		}
	}
	std::cout << "方阵X:\n";
	matrix_show(X, 2);
	std::cout << "方阵Y:\n";
	matrix_show(Y, 2);
	std::cout << "计算结果:\n";
	int** Z = matrix_multiply(X, Y, 2);
	matrix_show(Z, 2);
	return 0;
}

int** matrix_multiply(int** X, int** Y, int n)
{
	int** ret = new int* [n];
	for (int i = 0; i < n; i++)
	{
		ret[i] = new int [n]();
	}
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			for (int k = 0; k < n; k++)
			{
				ret[i][j] += X[i][k] * Y[k][j];
			}
		}
	}

	return ret;
}

void matrix_show(int** X, int n)
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			std::cout << X[i][j] << " ";
		}
		std::cout << std::endl;
	}
}

  显然时间复杂度为 O ( n 3 ) O(n^3) O(n3)

2 Strassen矩阵乘法

  对于方阵乘法,一个可能的想法是:
  1)划分两个方阵 A A A B B B为四个子方阵
  2)分别计算四个子区域的值

  此时我们需要计算8次子方阵的乘法和4次子方阵的加法,而每两个子方阵之间的乘法消耗 O ( N 3 8 ) O(\frac{N^3}{8}) O(8N3),再来4次加法,这不更多了吗?
  显然,这样的分治不是我们想要的,因为每一次递归都有8次子递归操作。
  对此,Strassen方法设计以下操作,使得递归次数减少1次

  其中:

  看起来还是复杂哈哈哈,不过最终的时间复杂度约为 O ( N 2.8074 ) O(N^{2.8074}) O(N2.8074)。需要说明的是,该方法在以下情况下不适用
  1)使用的常数多,对于典型应用,依然是朴素方法更佳
  2)稀疏矩阵有专门的方法
  3)递归的子矩阵需要额外的空间
  4)由于计算机对非整数值的运算精度有限,因此累计误差更大

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值