Strassen算法
如题,该算法是来自德国的牛逼的数学家strassen搞出来的,因为把n*n矩阵之间的乘法复杂度降低到n^(lg7)(lg的底是2),一开始想当然地认为朴素的做法是n^3,哪里还能有复杂度更低的做法,但是牛逼的strassen先生简直刷新了我的线性代数观和算法观
好吧,回来添一句:其实这个好理解,为何我一开始认为朴素计算方法是唯一的做法(而且为何还有strassen这样复杂度进一步降低的算法),举个例子:(A+B)(C+D),怎么做合适?先加后乘:两次加法,一次乘法;先乘后加:经历四次乘法和四次加法。可见,不同的计算步骤,计算代价是不同的。strassen就是玩这种拆拆合合的玩意儿搞出来这么个算法,不过人家那数学功底是真的好!
思路:基本的思路网上有,此处不再赘述,下面说说怎么实现strassen算法(数据处理)
m*n的矩阵和n*p的矩阵相乘,得到m*p的矩阵,因为每次要二分,遇到奇数的做法就是在行尾(列尾)加全零行(列),因为加入全零行(列)是不会影响就算结果的,从而使得可以二分。我为了省事直接在输入两个矩阵后就直接把它们统一扩展成了2^y*2^y的矩阵,其中,y=2^「lg(Max{m,p})」 (「」是向上取整,输入法里没找到合适的符号....;另外,Max(m,n)和Max(n,p)是相等的,取哪个都一样)
代码:
# include <iostream.h>
# include "..\Sort\IO_tools.cpp"
void strassen(int** &C,int** &A,int** &B,int arow,int acol,int brow,int bcol,int size);
void stra_plus(int** &C,int** &A,int** &B,int crow,int ccol,int arow,int acol,int brow,int bcol,int size,int symbol);
void main(){
int** A=NULL;int** B=NULL;int** C=NULL;
int A_row,A_col,B_row,B_col,size;
cout<<"size of A<row,col>:"<<endl;
cin>>A_row>>A_col;
size=input2A(A,A_row,A_col);//万能的传引用,绝对正确!
cout<<"size of B<row,col>:"<<endl;
cin>>B_row>>B_col;
input2A(B,B_row,B_col);//万能的传引用,绝对正确!
strassen(C,A,B,0,0,0,0,size);
output2A(C,A_row,B_col);
//stra_plus(C,A,B,0,0,0,0,0,0,size,1);
//output2A(C,size,size);
}
void strassen(int** &C,int** &A,int** &B,int arow,int acol,int brow,int bcol,int size){
C=(int**)new int* [size];
for(int i=0;i<size;i++){
C[i]=new int[size];
}
/*
对于size>1的要进一步拆分(其实strassen算法递归计算时要申请这么多内存,size不够大时反而降低了效率,
故而size达到下限时可以采用朴素的矩阵乘法计算方法而不必继续调用strassen算法,此处出于偷懒就省点事儿把size下限设为1)
*/
if(size>1){
//S(1-10)初始化
int** S1=NULL;int** S2=NULL;int** S3=NULL;int** S4=NULL;int** S5=NULL;int** S6=NULL;int** S7=NULL;int** S8=NULL;int** S9=NULL;int** S10=NULL;
stra_plus(S1,B,B,0,0,brow,bcol+size/2,brow+size/2,bcol+size/2,size/2,-1);
stra_plus(S2,A,A,0,0,arow,acol,arow,acol+size/2,size/2,1);
stra_plus(S3,A,A,0,0,arow+size/2,acol,arow+size/2,acol+size/2,size/2,1);
stra_plus(S4,B,B,0,0,brow+size/2,bcol,brow,bcol,size/2,-1);
stra_plus(S5,A,A,0,0,arow,acol,arow+size/2,acol+size/2,size/2,1);
stra_plus(S6,B,B,0,0,brow,bcol,brow+size/2,bcol+size/2,size/2,1);
stra_plus(S7,A,A,0,0,arow,acol+size/2,arow+size/2,acol+size/2,size/2,-1);
stra_plus(S8,B,B,0,0,brow+size/2,bcol,brow+size/2,bcol+size/2,size/2,1);
stra_plus(S9,A,A,0,0,arow,acol,arow+size/2,acol,size/2,-1);
stra_plus(S10,B,B,0,0,brow,bcol,brow,bcol+size/2,size/2,1);
//P(1-7)初始化
int** P1=NULL;int** P2=NULL;int** P3=NULL;int** P4=NULL;int** P5=NULL;int** P6=NULL;int** P7=NULL;
strassen(P1,A,S1,arow,acol,0,0,size/2);
strassen(P2,S2,B,0,0,brow+size/2,bcol+size/2,size/2);
strassen(P3,S3,B,0,0,brow,bcol,size/2);
strassen(P4,A,S4,arow+size/2,acol+size/2,0,0,size/2);
strassen(P5,S5,S6,0,0,0,0,size/2);
strassen(P6,S7,S8,0,0,0,0,size/2);
strassen(P7,S9,S10,0,0,0,0,size/2);
//计算结果C(依次是C11,C12,C21,C22)
stra_plus(C,P4,P5,0,0,0,0,0,0,size/2,1);stra_plus(C,C,P2,0,0,0,0,0,0,size/2,-1);stra_plus(C,C,P6,0,0,0,0,0,0,size/2,1);
stra_plus(C,P1,P2,0,size/2,0,0,0,0,size/2,1);
stra_plus(C,P3,P4,size/2,0,0,0,0,0,size/2,1);
stra_plus(C,P5,P1,size/2,size/2,0,0,0,0,size/2,1);stra_plus(C,C,P3,size/2,size/2,size/2,size/2,0,0,size/2,-1);stra_plus(C,C,P7,size/2,size/2,size/2,size/2,0,0,size/2,-1);
}
/*到达下限*/
else{
C[0][0]=A[arow][acol]*B[brow][bcol];
}
}
//参与运算的是A,B,C的size*size的(子)矩阵,<arow,acol>是A的参与运算的子矩阵的左上角坐标,<brow,bcol>同理,C是保存结果的
void stra_plus(int** &C,int** &A,int** &B,int crow,int ccol,int arow,int acol,int brow,int bcol,int size,int symbol){
if(C==NULL){
C=(int**)new int* [size];
for(int i=0;i<size;i++){
C[i]=new int[size];
}
}
for(int i=0;i<size;i++){
for(int j=0;j<size;j++){
C[i+crow][j+ccol]=A[i+arow][j+acol]+symbol*B[i+brow][j+bcol];
}
}
}
# include <iostream.h>
# include <stdlib.h>
# include <math.h>
int get_Upper_2Pow(int row,int col);
void inputA(int A[],int n){
int i=n;
cout<<"Input Array:";
while(i--){
cin>>A[n-i-1];
}
}
void outputA(int A[],int n){
int i=n;
cout<<"output Array:";
while(i--){
cout<<A[n-i-1]<<" ";
}
cout<<endl;
}
int input2A(int** &A,int row,int col){
int size=get_Upper_2Pow(row,col);
A=(int**)new int* [size];
for(int i=0;i<size;i++){
A[i]=new int[size];
}
cout<<"Input 2th Array:"<<endl;
for(int r=0;r<size;r++){
for(int c=0;c<size;c++){
A[r][c]=0;
}
}
for(r=0;r<row;r++){
for(int c=0;c<col;c++){
cin>>A[r][c];
}
}
return size;
}
void output2A(int** A,int row,int col){
cout<<"output:"<<endl;
for(int r=0;r<row;r++){
for(int c=0;c<col;c++){
cout<<A[r][c]<<" ";
}
cout<<endl;
}
}
int get_Upper_2Pow(int row,int col){
for(int i=0;pow(2,i)<row||pow(2,i)<col;i++);
return (int)pow(2,i);
}
Strassen算法的更多相关文章
- Conquer and Divide经典例子之Strassen算法解决大型矩阵的相乘
在通过汉诺塔问题理解递归的精髓中我讲解了怎么把一个复杂的问题一步步recursively划分了成简单显而易见的小问题.其实这个解决问题的思路就是算法中常用的divide and conquer, 这篇 ...
- 第四章 分治策略 4.2 矩阵乘法的Strassen算法
package chap04_Divide_And_Conquer; import static org.junit.Assert.*; import java.util.Arrays; import ...
- 4-2.矩阵乘法的Strassen算法详解
题目描述 请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法. 思路分析 根据wikipedia上的介绍:两个矩阵的乘法仅当第一个矩阵B的列数和另一个矩阵A的行数相等时才能定义.如A是m×n矩阵和B ...
- 《算法导论》——矩阵乘法的Strassen算法
前言: 很多朋友看到我写的<算法导论>系列,可能会觉得云里雾里,不知所云.这里我再次说明,本系列博文时配合<算法导论>一书,给出该书涉及的算法的c++实现.请结合<算法导 ...
- 算法导论-矩阵乘法-strassen算法
目录 1.矩阵相乘的朴素算法 2.矩阵相乘的strassen算法 3.完整测试代码c++ 4.性能分析 5.参考资料 内容 1.矩阵相乘的朴素算法 T(n) = Θ(n3) 朴素矩阵相乘算法,思想明了 ...
- 【算法导论C++代码】Strassen算法
简单方阵矩乘法 SQUARE-MATRIX-MULTIPLY(A,B) n = A.rows let C be a new n*n natrix to n to n cij = to n cij=ci ...
- 整数快速乘法/快速幂+矩阵快速幂+Strassen算法
快速幂算法可以说是ACM一类竞赛中必不可少,并且也是非常基础的一类算法,鉴于我一直学的比较零散,所以今天用这个帖子总结一下 快速乘法通常有两类应用:一.整数的运算,计算(a*b) mod c 二.矩 ...
- 【C++】Strassen算法代码
本文仅代码,无理论解释 实话实说,我觉得这个算法在C系列的语言下,简直垃圾到爆炸--毕竟是一群完全不懂程序数学家对着纸弄出来的,看起来好像非常的有用,实际上耗时是非常爆炸的. 但是<算法导论&g ...
- 【算法导论】--分治策略Strassen算法(运用下标运算)【c++】
由于偷懒不想用泛型,所以直接用了整型来写了一份 ①首先你得有一个矩阵的class Matrix ②Matrix为了方便用下标进行运算, Matrix的结构如图:(我知道我的字丑...) Matrix. ...
随机推荐
- Android模拟器使用教程
Using the Emulator In this document Overview Android Virtual Devices and the Emulator Starting and S ...
- poj 动态规划题目列表及总结
此文转载别人,希望自己能够做完这些题目! 1.POJ动态规划题目列表 容易:1018, 1050, 1083, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 11 ...
- 大数据工具——Splunk
Splunk是机器数据的引擎.使用 Splunk 可收集.索引和利用所有应用程序.服务器和设备(物理.虚拟和云中)生成的快速移动型计算机数据 .从一个位置搜索并分析所有实时和历史数据. 使用 Splu ...
- c#中获取服务器IP,客户端IP以及Request.ServerVariables详细说明
客户端ip: Request.ServerVariables.Get("Remote_Addr").ToString(); 客户端主机名: Request.ServerVaria ...
- Strongly connected 挺简单的tarjan
题意:给你一个连通图,问你最多加多少条边,还能保证该图不是强连通图. 对整个图求强连通分量,然后对图缩点,记录一下缩点之后每隔点包含的原来的点的个数,找出最少的那个点,然后对这个点建成完全图,对另外的 ...
- singleton单例模式
单例设计模式 单例设计模式概述 单例模式就是要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供 优点: 在系统内存中只存在一个对象,因此可以解决系统资源,对于一些需要频繁 ...
- java注解Annotation
扯扯注解的蛋 为什么学习注解?学习注解有什么好处?学完能做什么? 1.能够读懂别人的代码,特别是框架相关的代码 2.让编程更加简洁,代码更加清晰 3.让别人高看你一眼 注解是java1.5引入的 概念 ...
- iso中第三方框架SDWebImage的使用步骤
一.SDWebImage的使用 1.依赖的框架 * ImageIO.framework * MapKit.framework 2.UIImageView下载图片需要的头文件:UIImageView+W ...
- 最大熵模型 Maximum Entropy Model
熵的概念在统计学习与机器学习中真是很重要,熵的介绍在这里:信息熵 Information Theory .今天的主题是最大熵模型(Maximum Entropy Model,以下简称MaxEnt),M ...
- php里少用到的session_module_name,以及session的key值限制,简单将session存储为json格式数据的方法
这个函数的作用就是动态的设置php.ini里的session_save_handler,配合session_set_savepath可以在程序里自由配置session的后台方式. session_ca ...