【算法导论】笔记-第三章 分治策略

第3章 分治策略

  • 步骤:
    • 分解
    • 解决
    • 合并
  • 递归情况:当子问题足够大
  • 基本情况:当子问题足够小
  • 递归式:刻画分治算法的运行时间
  • 求解递归式的方法:
    • 代入法
    • 递归树法
    • 主方法

3.1 最大子数组

  • 例题: 买股票,使利益最大化

  • 思路:低价买进,高价卖出

  • 暴力解决问题:尝试每对可能的买进和卖出日期组合。n天中共有 ( 2 n ) (_2^n) (2n)种日期组合。运行时间为 Ω ( n 2 ) \Omega(n^2) Ω(n2)

  • 问题变换:寻找一段日期,使得从第一天到最后一天的股票净变值。问题转化为寻找A的和最大的非空连续子数组。称这样的连续子数组为最大子数组

  • 使用分治策略的求解方法:将子数组划分为两个规模尽量相等的子数组,分别求解两个子数组的最大子数组。

    FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high)

    left-sum = 负无穷
    sum = 0
    for i = mid downto low
        sum = sum + A[i]
        if sum > left-sum
            left-sum = sum
            max-left = i
    
    right-sum = 负无穷
    sum = 0
    for j = mid + 1 to high
        sum = sum + A[j]
        if sum > right-sum
            right-sum = sum
            max-right = j
    return(max-left, max-right, left-sum + reght-sum)
    

    FIND-MAXIMUN-SUBARRAY(A, low, high)

    if high == low
        return(low, high, A[low])
    else mid=(low+high)/2的下限
        (left-low, left-high, left-sum) = FIND-MAXIMUM-SUBARRAY(A, low, mid)
        (right-low, right-high, right-sum) = FIND-MAXIMUM-SUBARRAY(A, mid+1, high)
        (cross-low, cross-high, cross-sum) = FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high)
        if left-sum>=right-sum and left-sum>=cross-sum
            return (left-low, left-high, left-sum)
        elseif right-sum>=left-sum and right-sum>=cross-sum
            return (right-low, right-high, right-sum)
        else return (cross-low, cross-high, cross-sum)
    
  • python代码

    def FIND_MAX_CROSSING_SUBARRAY(A, low, mid, high):
        left_sum = 0
        sum = 0
        for i in range(low, mid):
            sum = sum + A[i]
            if sum > left_sum:
                left_sum = sum
        right_sum = 0
        sum = 0
        for j in range(mid+1, high):
            sum = sum + A[j]
            if sum > right_sum:
                right_sum = sum
        return left_sum, right_sum, left_sum + right_sum
    
    def FIND_MAXIMUM_SUBARRAY(A, low, high):
        if high == low:
            return low, high, A[low]
        else:
            mid = (low+high)//2
            left_low, left_high, left_sum = FIND_MAXIMUM_SUBARRAY(A, low, mid)
            right_low, right_high, right_sum = FIND_MAXIMUM_SUBARRAY(A, mid+1, high)
            cross_low, cross_high, cross_sum = FIND_MAX_CROSSING_SUBARRAY(A, low, mid, high)
        if left_sum>=right_sum and left_sum>=cross_sum:
            return left_low, left_high, left_sum
        elif right_sum>=left_sum and right_sum>=cross_sum:
            return right_low, right_high, right_sum
        else:
            return cross_low, cross_high, cross_sum
        
    B = [2,4,5,-3,-5,2,-6,2,7,-5,4,1,3,6,-9,-2,-4,8]
    B_low = 0
    B_high = 16
    B_mid = 8
    print(FIND_MAXIMUM_SUBARRAY(B, B_low, B_high))
    
  • 分治算法的分析

    • 运行时间:
      { θ , n = 1 2 T ( n / 2 ) + θ ( n ) , n > 1 \left\{ \begin{array}{c} \theta,n=1\\ 2T(n/2)+\theta(n),n>1 \end{array} \right. { θ,n=12T(n/2)+θ(n),n>1

3.2 矩阵乘法的Strassen算法

  • SQUARE-MATRIX-MULTIPLY(A,B)

    n = A.rows
    let C be a new n×n matrix
    for i = 1 to n
        for j = 1 to n
            Cij = 0
            for k = 1 to n
                Cij = Cij + aik * bkj
    return C
    
  • 运行时间: θ ( n 3 ) \theta(n^3) θ(n3)

  • 分治算法:

    • 伪代码:SQUARE-MATRIX-MULTIPLY-RECURSIVE(A,B)

      n = A.rows
      let C be a new n×n matrix
      if n == 1
          c11=a11 * b11
      else partition A, B, and C as in equations(4,9)
          C11=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A11,B11) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A12,B21)
          C12=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A11,B12) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A12,B22)
          C21=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A21,B11) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A22,B21)
          C22=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A21,B12) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A22,B22)
      return C
      
    • 运行时间:
      T ( n ) = { θ ( 1 ) , n = 1 8 T ( n / 2 ) + θ ( n 2 ) , n > 1 T(n)=\left\{ \begin{array}{c} \theta(1),n=1\\ 8T(n/2)+\theta(n^2),n>1 \end{array} \right. T(n)={ θ(1),n=18T(n/2)+θ(n2),n>1

  • Strassen方法

    • 步骤:

      • 将输入矩阵A,B和输出矩阵C各分解为四个 n / 2 × n / 2 n/2\times n/2 n/2×n/2的子矩阵。
      • 创建10个 n / 2 × n / 2 n/2\times n/2 n/2×n/2的空矩阵 S 1 , S 2 , ⋅ ⋅ ⋅ , S 10 S_1,S_2,···,S_{10} S1,S2,,S10,每个矩阵保存步骤1中创建的两个子矩阵的和与差。花费时间为 θ ( n 2 ) \theta(n^2) θ(n2)
      • 用步骤1中创建的子矩阵和步骤2中创建的10个矩阵,递归地计算7个矩阵积 P 1 , P 2 , ⋅ ⋅ ⋅ , P 7 P_1,P_2,···,P_7 P1,P2,,P7。每个矩阵 P i P_i Pi都是 n / 2 × n / 2 n/2\times n/2 n/2×n/2的。
      • 通过 P i P_i Pi矩阵的不同组合进行加减运算,计算出结果矩阵C的子矩阵 C 11 , C 12 , C 21 , C 22 C_{11},C_{12},C_{21},C_{22} C11,C12,C21,C22。花费时间 θ ( n 2 ) \theta(n^2) θ(n2)
    • 运行时间:
      T ( n ) = { θ ( 1 ) , n = 1 7 T ( n / 2 ) + θ ( n 2 ) , n > 1 T(n)=\left\{ \begin{array}{c} \theta(1),n=1\\ 7T(n/2)+\theta(n^2),n>1 \end{array} \right. T(n)={ θ(1),n=17T(n/2)+θ(n2),n>1

3.3 用代入法求解递归式

  • 代入法求解递归式:
    • 步骤:
      • 猜测解的形式
      • 用数学归纳法求出解中的常数,并证明解是正确的
  • 做出好的猜测
  • 避免陷阱
  • 改变变量

3.4 用递归树方法求解递归式

  • 递归树中,每个结点表示一个单一子问题的代价,子问题对应某次递归函数调用。创建递归树之后,对树的每层的各子问题的代价进行求和,得到每一层的代价,然后将所有层的代价加起来,得到整棵递归树的总代价,这个总代价就是递归式的解。

3.5 用主方法求解递归式

  • 主定理:令 a≥1和b>1是常数, f ( n ) f(n) f(n)是一个函数, T ( n ) T(n) T(n)是定义在非负整数上的递归式: T ( n ) = a T ( n / b ) + f ( n ) T(n) = aT(n/b) + f(n) T(n)=aT(n/b)+f(n)

你可能感兴趣的:(算法导论,算法,数据结构,算法导论,分治算法)