通过汉诺塔问题理解递归的精髓中我讲解了怎么把一个复杂的问题一步步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.

关键点就是这些,附上代码吧。

    1. //multiply matrix multiplication
    2. import java.util.Scanner;
    3. public class Strassen{
    4. public Strassen(){}
    5. /** split a parent matrix into child matrics8*/
    6. public static void split(int[][] P, int[][] C, int iB, int jB){
    7. for(int i1=0, i2 = iB; i1<C.length; i1++, i2++)
    8. for(int j1=0, j2=jB; j1<C.length; j1++, j2++)
    9. C[i1][j1] = P[i2][j2];
    10. }
    11. /**join child matric into parent matrix*/
    12. public static void join(int[][] C, int[][] P, int iB, int jB){
    13. for(int i1=0, i2 = iB; i1<C.length; i1++, i2++)
    14. for(int j1=0, j2=jB; j1<C.length; j1++, j2++)
    15. P[i2][j2]=C[i1][j1];
    16. }
    17. /**add two matrics into one*/
    18. public static int[][] add(int[][] A, int[][] B){
    19. //A and B has the same dimension
    20. int n = A.length;
    21. int[][] C = new int[n][n];
    22. for (int i=0; i<n; i++)
    23. for(int j=0; j<n; j++)
    24. C[i][j] = A[i][j] + B[i][j];
    25. return C;
    26. }
    27. //subtract one matric by another
    28. public static int[][] sub(int[][] A, int[][] B){
    29. //A and B has the same dimension
    30. int n = A.length;
    31. int[][] C = new int[n][n];
    32. for (int i=0; i<n; i++)
    33. for(int j=0; j<n; j++)
    34. C[i][j] = A[i][j] - B[i][j];
    35. return C;
    36. }
    37. //Multiply matrix
    38. public static int[][] multiply(int[][] A, int[][] B){
    39. int n = A.length;
    40. int[][] R = new int[n][n];
    41. /**exit*/
    42. if(n==1)
    43. R[0][0] = A[0][0]+B[0][0];
    44. else{
    45. //divide A into 4 submatrix
    46. int[][] A11 = new int[n/2][n/2];
    47. int[][] A12 = new int[n/2][n/2];
    48. int[][] A21 = new int[n/2][n/2];
    49. int[][] A22 = new int[n/2][n/2];
    50. split(A, A11, 0, 0);
    51. split(A, A12, 0, n/2);
    52. split(A, A21, n/2, 0);
    53. split(A, A22, n/2, n/2);
    54. //divide B into 4 submatric
    55. int[][] B11 = new int[n/2][n/2];
    56. int[][] B12 = new int[n/2][n/2];
    57. int[][] B21 = new int[n/2][n/2];
    58. int[][] B22 = new int[n/2][n/2];
    59. split(B, B11, 0, 0);
    60. split(B, B12, 0, n/2);
    61. split(B, B21, n/2, 0);
    62. split(B, B22, n/2, n/2);
    63. //seven magic products
    64. int[][] P1 = multiply(A11, sub(B12, B22));
    65. int[][] P2 = multiply(add(A11,A12), B22);
    66. int[][] P3 = multiply(add(A21, A22), B11);
    67. int[][] P4 = multiply(A22, sub(B21, B11));
    68. int[][] P5 = multiply(add(A11, A22), add(B11, B22));
    69. int[][] P6 = multiply(sub(A12, A22), add(B21, B22));
    70. int[][] P7 = multiply(sub(A11, A21), add(B11, B12));
    71. //new 4 submatrix
    72. int[][] R11 = add(add(P5, sub(P4, P2)), P6);
    73. int[][] R12 = add(P1, P2);
    74. int[][] R21 = add(P3, P4);
    75. int[][] R22 = sub(sub(add(P1, P5), P3), P7);
    76. //joint together
    77. join(R11, R, 0, 0);
    78. join(R12, R, 0, n/2);
    79. join(R21, R, n/2, 0);
    80. join(R22, R, n/2, n/2);
    81. }
    82. return R;
    83. }
    84. //main
    85. public static void main(String[] args){
    86. Scanner scan = new Scanner(System.in);
    87. System.out.println("Strassen Multiplication Algorithm Test\n");
    88. Strassen s = new Strassen();
    89. System.out.println("Fetch the matric A and B...");
    90. int N = scan.nextInt();
    91. int[][] A = new int[N][N];
    92. int[][] B = new int[N][N];
    93. for (int i = 0; i < N; i++)
    94. for (int j = 0; j < N; j++)
    95. A[i][j] = scan.nextInt();
    96. for (int i = 0; i < N; i++)
    97. for (int j = 0; j < N; j++)
    98. B[i][j] = scan.nextInt();
    99. System.out.println("Fetch Completed!");
    100. int[][] C = s.multiply(A, B);
    101. System.out.println("\nmatrices A = ");
    102. for (int i = 0; i < N; i++){
    103. for (int j = 0; j < N; j++)
    104. System.out.print(A[i][j] +" ");
    105. System.out.println();
    106. }
    107. System.out.println("\nmatrices B =");
    108. for (int i = 0; i < N; i++) {
    109. for (int j = 0; j < N; j++)
    110. System.out.print(B[i][j] +" ");
    111. System.out.println();
    112. }
    113. System.out.println("\nProduct of matrices A and  B  = ");
    114. for (int i = 0; i < N; i++)
    115. {
    116. for (int j = 0; j < N; j++)
    117. System.out.print(C[i][j] +" ");
    118. System.out.println();
    119. }
    120. }
    121. }

Conquer and Divide经典例子之Strassen算法解决大型矩阵的相乘的更多相关文章

  1. Conquer and Divide经典例子之汉诺塔问题

    递归是许多经典算法的backbone, 是一种常用的高效的编程策略.简单的几行代码就能把一团遭的问题迎刃而解.这篇博客主要通过解决汉诺塔问题来理解递归的精髓. 汉诺塔问题简介: 在印度,有这么一个古老 ...

  2. Strassen算法

    如题,该算法是来自德国的牛逼的数学家strassen搞出来的,因为把n*n矩阵之间的乘法复杂度降低到n^(lg7)(lg的底是2),一开始想当然地认为朴素的做法是n^3,哪里还能有复杂度更低的做法,但 ...

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

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

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

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

  5. C/C++中几种经典的垃圾回收算法

    1.引用计数算法 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1:当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明 ...

  6. python之路第五篇之递归(进阶篇:续:经典例子剖析)

    递归 在函数内部,可以调用其他函数; 如果一个函数在内部调用自身本身,这个函数就是递归函数. 例如,我们来计算阶乘: n! = 1 x 2 x 3 x ... x n, 用函数f1(n)表示,可以看出 ...

  7. jQuery监听事件经典例子

    关键字:jQuery监听事件经典例子  js代码:  ============================================================  $(function( ...

  8. 记录几个经典的字符串hash算法

    记录几个经典的字符串hash算法,方便以后查看: 推荐一篇文章: http://www.partow.net/programming/hashfunctions/# (1)暴雪字符串hash #inc ...

  9. C语言经典算法 - 多维矩阵转一维矩阵的代码

    下边内容内容是关于C语言经典算法 - 多维矩阵转一维矩阵的内容,应该能对码农也有好处. #include <stdio.h>#include <stdlib.h>int mai ...

随机推荐

  1. GeoServer中利用SLD配图之矢量图层配图

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1 背景 我们在ArcMap中可以直接通过symbol功能对图层进行定 ...

  2. Node.js、express、mongodb 实现分页查询、条件搜索

    前言 在上一篇Node.js.express.mongodb 入门(基于easyui datagrid增删改查) 的基础上实现了分页查询.带条件搜索. 实现效果 1.列表第一页. 2.列表第二页 3. ...

  3. Mongo查询

    这里主要是讲MongoDB在控制台中如何进行高级查询. 还有一句想提醒大家,多动手实验,才是硬道理. <,>,>=,<= 这四个就不用解释了,最常用的,也是最简单的. db.c ...

  4. 用MVC做支付宝手机网页支付问题

    支付宝支付接口手机网页支付 从官网扒下来的demo阿里做得还是相当不错的,只要参数改正确了基本上都是能跑通,WebForm的没什么大问题,这次要讲的主要是几个要注意的问题,因为是用MVC来做. 1.要 ...

  5. what's this? 浅谈js中this的指向问题

    刚刚学习js的朋友可能和我一样,看到代码中的this总是一脸懵逼,不知道this到底指向谁.经过一段时间的了解,我想跟大家分享下自己的理解. 何时出现this 函数在调用的时候,会自动获得两个特殊变量 ...

  6. Moon.Orm 5.0 (MQL版) 欣赏另一种Orm的设计风格----大道至简

    Moon.Orm 5.0(MQL版)使用指南(二) 一.使用sql及存储过程 1)使用List<Dictionary<))) 2)MQL 全面接触

  7. Github团队开发示例(二)

    Github团队开发示例(二) 作者:Grey 原文地址:http://www.cnblogs.com/greyzeng/p/6063765.html 接之前讲的Github团队开发示例(一),本文主 ...

  8. .NET开源高性能Socket通信中间件Helios介绍及演示

    一:Helios是什么 Helios是一套高性能的Socket通信中间件,使用C#编写.Helios的开发受到Netty的启发,使用非阻塞的事件驱动模型架构来实现高并发高吞吐量.Helios为我们大大 ...

  9. WPF老矣,尚能饭否——且说说WPF今生未来(中):策略

    本文接上文<WPF老矣,尚能饭否——且说说WPF今生未来(上):担心>继续. “上篇”中部分精彩的点评: 虽然WPF不再更新了,但是基于WPF的技术还是在发展着,就比如现在的WinRT,只 ...

  10. C# 超时工具类 第二版

    附源码,没有附测试demo 之前的工具类:C# 给某个方法设定执行超时时间 /// <summary> /// 超时工具 /// </summary> public class ...