算法导论学习笔记之二--分而治之(divide-and-conquer approach)

如果一个问题当它的规模缩小的时候,问题性质不变,并且问题的规模最小的时候简单可解,就可以采用divide-and-conquer 方法。

divide-and-conquer 分以下4步进行:

攻克: 如果问题足够小,可以直接给出答案

分解: 把问题分解成同样性质的几个子问题

递归:递归调用本算法来解决子问题
合并:把解决好的子问题合在一起,组成原有问题的答案


# 假设问题为p,问题的数据集为A,规模为N

# 解决下标从R到N的所有问题

divide-and-conquer-p(A,R, N)
    #攻克:问题足够小
    if R to N is small enough
        return Answer    
    
    #分解:把p分成m个子问题    
    (N1, N2, ..., Nm) = divide-p(A,R,N)    

     #递归: 解决m个子问题    
     Answer_N1 = divide-and-conquer-p(A, R, N1)  
     Answer_N2 = divide-and-conquer-p(A, N1+1, N2)     
     ...;
     Answer_N   = divide-and-conquer-p(A, Nm+1, N)  

     #合并:综合m个子问题的答案,给出整个问题的答案    
     return combine-p(Answer_N1, Answer_N2,..., Answer_N) 


例 1:用divide-and-conquer方法计算N个数的和

#分解
def divide_p(A, R, N):
    return (R + N) / 2
#合并    
def combine_p(subsum1, subsum2):
    return subsum1 + subsum2
    
def divide_and_conquer_p(A, R, N):
    if R==N:#攻克
        return A[R]
    #分解
    N1  = divide_p(A, R, N)
    #递归
    subsum1 = divide_and_conquer_p(A, R, N1)
    subsum2 = divide_and_conquer_p(A, N1+1, N)
    #合并
    return combine_p(subsum1, subsum2)
    

A = [10, 9, 8, 7, 6, 5, 4, 3, 2]
sum = divide_and_conquer_p(A, 0, 8)
print "sum is:", sum


例 2:已知整数数组A, 长度为N, 给出和最大的子数组。(子数组元素在原数组中连续)

# 计算和最大的子数组
def divide_a(low, high):
    return (low + high) / 2

def combine_a(left_sub, right_sub, cross_sub):
    if left_sub[2] > right_sub[2] and left_sub[2] > cross_sub[2]:
        return left_sub
    elif right_sub[2] > left_sub[2] and right_sub[2] > cross_sub[2]:
        return right_sub
    else:
        return cross_sub
def find_max_cross(A, low, high, mid):
    left_sum = 0
    left_max_sum =A[mid]
    left_max_low = mid
    for i in range(mid, low-1, -1):
        left_sum = A[i] + left_sum
        if left_max_sum < left_sum :
            left_max_low = i
            left_max_sum = left_sum
    right_sum = 0
    right_max_sum = A[mid + 1]
    right_max_high = mid + 1 
    for i in range(mid + 1, high+1):
        right_sum = A[i] + right_sum
        if right_max_sum < right_sum:
            right_max_high = i;
            right_max_sum = right_sum;
    print (left_max_low, right_max_high, left_max_sum + right_max_sum)
    return (left_max_low, right_max_high, left_max_sum + right_max_sum)
    
        
def divide_and_conquer_a(A, low, high):
    #攻克
    if low == high:
        return (low, high, A[low])
    #分解
    mid = divide_a(low, high)
    #递归
    left_sub = divide_and_conquer_a(A, low, mid)
    right_sub = divide_and_conquer_a(A, mid+1, high)
    cross_sub = find_max_cross(A, low, high, mid)
    #合并
    return combine_a(left_sub, right_sub, cross_sub)

if __name__ == "__main__":
    A = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
    t = divide_and_conquer_a(A,0,15)
    print t


你可能感兴趣的:(算法,算法导论)