分治策略

来源:互联网 发布:全国矢量数据 编辑:程序博客网 时间:2024/05/29 15:09

分治策略

步骤:

  1. 分解
  2. 解决
  3. 合并

    递归情况和基本情况:求解递归式时,可以使用三种方法,a 代入法 b 递归树法 c 主方法

最大子数组

A[low..high]的任何连续子数组A[i..j]所处的位置必然是以下几个情况之一:

  1. 完全位于子数组A[low..mid] low<=i<=j<=mid
  2. 完全位于子数组A[mid..high] mid
FIND_MAX_CROSSING_SUBARRAY(A, low, mid, high)left_sum = -无穷sum = 0for i = mid downto low    sum = sum + A[i]    if (sum > left_sum)        left_sum = sum        max_left = iright_sum = -无穷sum = 0for j = mid+1 to high    sum = sum + A[j]    if (sum > right_sum)        right_sum = sum        max_right = jreturn (max_left, max_right, left_sum + right_sum)

接下来,就能给出最大子数组问题的分治算法伪代码了

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_right, cross_sum) = FIND_MAX_CROSSING_SUBARRAY(A, low, mid, high)    if (left_sum >= right_sum && left_sum >= cross_sum)        return (left_low, left_high, left_sum)    else if (right_sum >= left_sum && right_sum >= cross_sum)        return (right_low, right_high, right_sum)    else        return (cross_low, cross_high, cross_sum)

可以通过计算递归式发现,分治方法得到的这个最大子数组问题的时间复杂度优于暴力求解的O(n*n),得到的时间复杂度为O(n*lgn)

简单实现下:

#include <stdio.h>#include <stdlib.h>void result_save(int result[], int source[]);void find_maximum_subarray(int A[], int low, int high, int result[]);void find_max_crossing_subarray(int A[], int low, int mid, int high, int result[]);void find_max_crossing_subarray(int A[], int low, int mid, int high, int result[]){    int max_left;    int max_right;    int left_sum = -1;    int sum = 0;    for (int i = mid; i >= low; --i) {      //left        sum += A[i];         if (sum > left_sum) {            left_sum = sum;             max_left = i;         }    }    int right_sum = -1;    sum = 0;    for (int j = mid+1; j <= high; ++j) {        sum += A[j];         if (sum > right_sum) {            right_sum = sum;             max_right = j;        }    }    result[0] = max_left;    result[1] = max_right;    result[2] = left_sum + right_sum; //sum}void find_maximum_subarray(int A[], int low, int high, int result[]){    if (low == high) {        result[0] = low;        result[1] = high;        result[2] = A[low];    } else {        int mid = (low + high)/2;        int result1[3] = {0, 0, 0};        find_maximum_subarray(A, low, mid, result1);        int result2[3] = {0, 0, 0};        find_maximum_subarray(A, mid+1, high, result2);        int result3[3] = {0, 0, 0};        find_max_crossing_subarray(A, low, mid, high, result3);        if (result1[2] >= result2[2] && result1[2] >= result3[2])            result_save(result, result1);         else if (result2[2] >= result1[2] && result2[2] >= result3[2])            result_save(result, result2);        else            result_save(result, result3);    }}void result_save(int result[], int source[]){    result[0] = source[0];    result[1] = source[1];    result[2] = source[2];}int main(void){    int A[16] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};    int result[3] = {0, 0, 0};    find_maximum_subarray(A, 0, 15, result);    printf("the max sum is %d\n", result[2]);    printf("the maximum number array is : ");    for (int i = result[0]; i <= result[1]; ++i)        printf("%d ", A[i]);    exit(0);}
0 0