如题,该算法是来自德国的牛逼的数学家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算法的更多相关文章

  1. Conquer and Divide经典例子之Strassen算法解决大型矩阵的相乘

    在通过汉诺塔问题理解递归的精髓中我讲解了怎么把一个复杂的问题一步步recursively划分了成简单显而易见的小问题.其实这个解决问题的思路就是算法中常用的divide and conquer, 这篇 ...

  2. 第四章 分治策略 4.2 矩阵乘法的Strassen算法

    package chap04_Divide_And_Conquer; import static org.junit.Assert.*; import java.util.Arrays; import ...

  3. 4-2.矩阵乘法的Strassen算法详解

    题目描述 请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法. 思路分析 根据wikipedia上的介绍:两个矩阵的乘法仅当第一个矩阵B的列数和另一个矩阵A的行数相等时才能定义.如A是m×n矩阵和B ...

  4. 《算法导论》——矩阵乘法的Strassen算法

    前言: 很多朋友看到我写的<算法导论>系列,可能会觉得云里雾里,不知所云.这里我再次说明,本系列博文时配合<算法导论>一书,给出该书涉及的算法的c++实现.请结合<算法导 ...

  5. 算法导论-矩阵乘法-strassen算法

    目录 1.矩阵相乘的朴素算法 2.矩阵相乘的strassen算法 3.完整测试代码c++ 4.性能分析 5.参考资料 内容 1.矩阵相乘的朴素算法 T(n) = Θ(n3) 朴素矩阵相乘算法,思想明了 ...

  6. 【算法导论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 ...

  7. 整数快速乘法/快速幂+矩阵快速幂+Strassen算法

    快速幂算法可以说是ACM一类竞赛中必不可少,并且也是非常基础的一类算法,鉴于我一直学的比较零散,所以今天用这个帖子总结一下 快速乘法通常有两类应用:一.整数的运算,计算(a*b) mod c  二.矩 ...

  8. 【C++】Strassen算法代码

    本文仅代码,无理论解释 实话实说,我觉得这个算法在C系列的语言下,简直垃圾到爆炸--毕竟是一群完全不懂程序数学家对着纸弄出来的,看起来好像非常的有用,实际上耗时是非常爆炸的. 但是<算法导论&g ...

  9. 【算法导论】--分治策略Strassen算法(运用下标运算)【c++】

    由于偷懒不想用泛型,所以直接用了整型来写了一份 ①首先你得有一个矩阵的class Matrix ②Matrix为了方便用下标进行运算, Matrix的结构如图:(我知道我的字丑...) Matrix. ...

随机推荐

  1. Ubuntu 12.04 LTS(64bit) 环境下JDK、 Eclipse、 ADT、 快捷图标

    一.在FriendlyARM,Tiny4412,,安装包下可补充: (按照手册添加openjdk-6-jdk 后) 安装JDK (Java),选择需要的JDK,或者全部安装. a) OpenJDK-6 ...

  2. JavaScript 高级篇之闭包、模拟类,继承(五)

    本篇主要分享我对闭包的理解及使用闭包完成私有属性.模拟类.继承等,结合大量例子,希望大家能快速掌握!首先让我们先从一些基本的术语开始吧     一.javascript中的闭包 1.我们一起先来理解什 ...

  3. ubuntu中apt-get安装与默认路径

    一.apt-get 安装 deb是debian linus的安装格式,跟red hat的rpm非常相似,最基本的安装命令是:dpkg -i file.deb或者直接双击此文件 dpkg 是Debian ...

  4. jquery来跨域提交表单

    说说用jquery来实现跨域提交表单 在jQuery中,我们使用json数据类型,通过getJSON方法来实现从服务端获取或发送数据,而当要向不同远程服务器端提交或者获取数据时,要采用jsonp数据类 ...

  5. tc srm 636 div2 500

    100的数据直接暴力就行,想多了... ac的代码: #include <iostream> #include <cstdio> #include <cstring> ...

  6. datagridview的某些属性以及增删改查

    private void button1_Click(object sender, EventArgs e) //查询 { dataGridView1.AutoGenerateColumns = fa ...

  7. C语言之字节对齐

    在C语言编程中,有时为了达到减少运行的时间的目的,需要浪费一些空间:而有时为了节省空间,使它的运行时间增长.而字节对齐则是为了访问效率,用空间换取时间. 要掌握字节对齐,首先得明确一下四个概念: 1. ...

  8. 免费Gif图片录制工具

    /************************************************************************* * 免费Gif图片录制工具 * 说明: * 最近在 ...

  9. 【英语】Bingo口语笔记(76) - 不知如何应答的场景对话

  10. 【解题报告】[动态规划] RQNOJ - PID105 / 核电站问题

    原题地址:http://www.rqnoj.cn/problem/105 解题思路: 状态表示: 数组dp[i][j]中的j拆成M位二进制(后缀B表示). 如:M=3时 dp[5][000B]表示第3 ...