Conquer and Divide经典例子之Strassen算法解决大型矩阵的相乘
在通过汉诺塔问题理解递归的精髓中我讲解了怎么把一个复杂的问题一步步recursively划分了成简单显而易见的小问题。其实这个解决问题的思路就是算法中常用的divide and conquer, 这篇日志通过解决矩阵的乘法,来了解另外一个基本divide and conque思想的strassen算法。
矩阵A乘以B等于X, 则Xij =
注意左乘右乘的区别,AB 与BA是不同的。
如果r = 1, 直接就是两个数的相乘。
如果r = 2, 例如
X =
[ 1, 2;
3, 4];
Y =
[ 2, 3;
4, 5];
R = XY的计算十分简单,但是如果r很大,耗时是O(r^3)。为了简化,可以把X, Y各自划分成2X2的矩阵,每一个元素其实是有n/2行的矩阵
(注:这里仅讲解行数等于列数的情况。)
X =
[A, B;
C, D];
Y =
[E, F;
G, H]
所以XY =[
AE+BG, AF+BH;
CE+DG, CF+DH]
Strassen引入seven magic product 分别是P1, P2, P3 ,P4, P5, P6, P7
P1 = A(F-H)
P2 = (A+B)H
P3 = (C+D)E
P4 = D(G-E)
P5 = (A+D)(E+H)
P6 = (B-D)(G+H)
P7 = (A-C)(E+F)
这样XY =
[P5+P4-P2+P6, P1+P2;
P3+P4, P1+P5-P3-P7]
然后通过递归的策略计算矩阵的相乘,递归的出口是n = 1.
关键点就是这些,附上代码吧。
- //multiply matrix multiplication
- import java.util.Scanner;
- public class Strassen{
- public Strassen(){}
- /** split a parent matrix into child matrics8*/
- public static void split(int[][] P, int[][] C, int iB, int jB){
- for(int i1=0, i2 = iB; i1<C.length; i1++, i2++)
- for(int j1=0, j2=jB; j1<C.length; j1++, j2++)
- C[i1][j1] = P[i2][j2];
- }
- /**join child matric into parent matrix*/
- public static void join(int[][] C, int[][] P, int iB, int jB){
- for(int i1=0, i2 = iB; i1<C.length; i1++, i2++)
- for(int j1=0, j2=jB; j1<C.length; j1++, j2++)
- P[i2][j2]=C[i1][j1];
- }
- /**add two matrics into one*/
- public static int[][] add(int[][] A, int[][] B){
- //A and B has the same dimension
- int n = A.length;
- int[][] C = new int[n][n];
- for (int i=0; i<n; i++)
- for(int j=0; j<n; j++)
- C[i][j] = A[i][j] + B[i][j];
- return C;
- }
- //subtract one matric by another
- public static int[][] sub(int[][] A, int[][] B){
- //A and B has the same dimension
- int n = A.length;
- int[][] C = new int[n][n];
- for (int i=0; i<n; i++)
- for(int j=0; j<n; j++)
- C[i][j] = A[i][j] - B[i][j];
- return C;
- }
- //Multiply matrix
- public static int[][] multiply(int[][] A, int[][] B){
- int n = A.length;
- int[][] R = new int[n][n];
- /**exit*/
- if(n==1)
- R[0][0] = A[0][0]+B[0][0];
- else{
- //divide A into 4 submatrix
- int[][] A11 = new int[n/2][n/2];
- int[][] A12 = new int[n/2][n/2];
- int[][] A21 = new int[n/2][n/2];
- int[][] A22 = new int[n/2][n/2];
- split(A, A11, 0, 0);
- split(A, A12, 0, n/2);
- split(A, A21, n/2, 0);
- split(A, A22, n/2, n/2);
- //divide B into 4 submatric
- int[][] B11 = new int[n/2][n/2];
- int[][] B12 = new int[n/2][n/2];
- int[][] B21 = new int[n/2][n/2];
- int[][] B22 = new int[n/2][n/2];
- split(B, B11, 0, 0);
- split(B, B12, 0, n/2);
- split(B, B21, n/2, 0);
- split(B, B22, n/2, n/2);
- //seven magic products
- int[][] P1 = multiply(A11, sub(B12, B22));
- int[][] P2 = multiply(add(A11,A12), B22);
- int[][] P3 = multiply(add(A21, A22), B11);
- int[][] P4 = multiply(A22, sub(B21, B11));
- int[][] P5 = multiply(add(A11, A22), add(B11, B22));
- int[][] P6 = multiply(sub(A12, A22), add(B21, B22));
- int[][] P7 = multiply(sub(A11, A21), add(B11, B12));
- //new 4 submatrix
- int[][] R11 = add(add(P5, sub(P4, P2)), P6);
- int[][] R12 = add(P1, P2);
- int[][] R21 = add(P3, P4);
- int[][] R22 = sub(sub(add(P1, P5), P3), P7);
- //joint together
- join(R11, R, 0, 0);
- join(R12, R, 0, n/2);
- join(R21, R, n/2, 0);
- join(R22, R, n/2, n/2);
- }
- return R;
- }
- //main
- public static void main(String[] args){
- Scanner scan = new Scanner(System.in);
- System.out.println("Strassen Multiplication Algorithm Test\n");
- Strassen s = new Strassen();
- System.out.println("Fetch the matric A and B...");
- int N = scan.nextInt();
- int[][] A = new int[N][N];
- int[][] B = new int[N][N];
- for (int i = 0; i < N; i++)
- for (int j = 0; j < N; j++)
- A[i][j] = scan.nextInt();
- for (int i = 0; i < N; i++)
- for (int j = 0; j < N; j++)
- B[i][j] = scan.nextInt();
- System.out.println("Fetch Completed!");
- int[][] C = s.multiply(A, B);
- System.out.println("\nmatrices A = ");
- for (int i = 0; i < N; i++){
- for (int j = 0; j < N; j++)
- System.out.print(A[i][j] +" ");
- System.out.println();
- }
- System.out.println("\nmatrices B =");
- for (int i = 0; i < N; i++) {
- for (int j = 0; j < N; j++)
- System.out.print(B[i][j] +" ");
- System.out.println();
- }
- System.out.println("\nProduct of matrices A and B = ");
- for (int i = 0; i < N; i++)
- {
- for (int j = 0; j < N; j++)
- System.out.print(C[i][j] +" ");
- System.out.println();
- }
- }
- }
Conquer and Divide经典例子之Strassen算法解决大型矩阵的相乘的更多相关文章
- Conquer and Divide经典例子之汉诺塔问题
递归是许多经典算法的backbone, 是一种常用的高效的编程策略.简单的几行代码就能把一团遭的问题迎刃而解.这篇博客主要通过解决汉诺塔问题来理解递归的精髓. 汉诺塔问题简介: 在印度,有这么一个古老 ...
- Strassen算法
如题,该算法是来自德国的牛逼的数学家strassen搞出来的,因为把n*n矩阵之间的乘法复杂度降低到n^(lg7)(lg的底是2),一开始想当然地认为朴素的做法是n^3,哪里还能有复杂度更低的做法,但 ...
- 4-2.矩阵乘法的Strassen算法详解
题目描述 请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法. 思路分析 根据wikipedia上的介绍:两个矩阵的乘法仅当第一个矩阵B的列数和另一个矩阵A的行数相等时才能定义.如A是m×n矩阵和B ...
- 第四章 分治策略 4.2 矩阵乘法的Strassen算法
package chap04_Divide_And_Conquer; import static org.junit.Assert.*; import java.util.Arrays; import ...
- C/C++中几种经典的垃圾回收算法
1.引用计数算法 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1:当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明 ...
- python之路第五篇之递归(进阶篇:续:经典例子剖析)
递归 在函数内部,可以调用其他函数; 如果一个函数在内部调用自身本身,这个函数就是递归函数. 例如,我们来计算阶乘: n! = 1 x 2 x 3 x ... x n, 用函数f1(n)表示,可以看出 ...
- jQuery监听事件经典例子
关键字:jQuery监听事件经典例子 js代码: ============================================================ $(function( ...
- 记录几个经典的字符串hash算法
记录几个经典的字符串hash算法,方便以后查看: 推荐一篇文章: http://www.partow.net/programming/hashfunctions/# (1)暴雪字符串hash #inc ...
- C语言经典算法 - 多维矩阵转一维矩阵的代码
下边内容内容是关于C语言经典算法 - 多维矩阵转一维矩阵的内容,应该能对码农也有好处. #include <stdio.h>#include <stdlib.h>int mai ...
随机推荐
- Windows Server 2008 下解析二级域名的方法
昨天去了客户那里部署网站,用的是客户那边的windows server 2008. 本文主要以总结问题点的形式来说. 问题1:本机的数据库是SQL SERVER 2008R2,客户那边的数据库是SQL ...
- 详解用Navicat工具将Excel中的数据导入Mysql中
第一步:首先需要准备好有数据的excel: 第二步:选择"文件"->"另存为",保存为"CSV(逗号分隔)(*.csv)",将exce ...
- Redis 对比 Memcached 并在 CentOS 下进行安装配置
了解一下 Redis Redis 是一个开源.支持网络.基于内存.键值对的 Key-Value 数据库,使用 ANSI C 编写,并提供多种语言的 API ,它几乎没有上手难度,只需要几分钟我们就能完 ...
- 基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作
由于一个客户朋友的需求,需要我的Winform开发框架支持国产达梦数据库的操作,这个数据库很早就听过,但是真正一般项目用的很少,一般在一些特殊的项目可能需要用到.由于我的Winform开发框架,是基于 ...
- Web 上传图片加水印
上传图片加水印 需要使用控件FileUpload 上传按钮Image控件展示上传的图片,页面中拖入三个控件 <form id="form1" runat="serv ...
- sessionState与会话
HTTP 是一种无状态协议.这意味着 Web 服务器会将针对页面的每个 HTTP 请求作为独立的请求进行处理.ASP.NET 会话状态将来自限定时间范围内的同一浏览器的请求标识为一个会话,并提供用于在 ...
- 设计模式(一)单例模式(Singleton Pattern)
一.引言 最近在设计模式的一些内容,主要的参考书籍是<Head First 设计模式>,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了 ...
- PetaPoco4.0 实体某个字段不赋值会更新成null解决方案
最新用PetaPoco4.0做项目发现有个需求,就是比如说:在mvc表单中,只显示部分字段,一个表单还有其他状态等字段,没有显示到mvc页面上 但是当MVC收集表单提交更新的时候,会发现会把数据库中的 ...
- Asp.net 面向接口可扩展框架之使用“类型转化基础服务”测试四种Mapper(AutoMapper、EmitMapper、NLiteMapper及TinyMapper)
Asp.net 面向接口可扩展框架的“类型转化基础服务”是我认为除了“核心容器”之外最为重要的组成部分 但是前面博文一出,争议很多,为此我再写一篇类型转化基础服务和各种Mapper结合的例子,顺便对各 ...
- 开源UML工具推荐
1.StarUML StarUML是一个开源UML项目,可以开发快速,灵活,可扩展,多功能并且免费的UML/MDA平台.此项目运行在Win32平台之上.StarUML项目的目标是成为RationalR ...