思路: 将原数组递归分解为两个子数组,直到能求解出子解为止,再将答案合并。
难点:产生数组的最大子序列只有以下三种情况:
1.最大子序列为左子数组的最大子序列;
2.最大子序列为右子数组的最大子序列;
3.最大子序列为跨中点的最大子序列;(特殊情况)
依照以上三种情况分而治之即得解。
附上ac代码:
1 #include <stdio.h> 2 int a[100001]; 3 4 void subcross(int arr[], int *low, int *mid, int *high, int *sum){ 5 int s = 0, maxl = -1000 - 1, maxr = -1000 - 1, l, r; 6 for(int i = *mid; i >= *low; --i){ //以中点为基准,向左推进求最大左边界子序列 7 s += arr[i]; 8 if(s >= maxl){ 9 l = i; maxl = s; 10 } 11 } 12 for(int i = *mid + 1, s = 0; i <= *high; ++i){ //以中点为基准,向右推进求最大右边界子序列 13 s += arr[i]; 14 if(s > maxr){ 15 r = i; maxr = s; 16 } 17 } 18 *sum = maxl + maxr; //合并,传递参数 19 *low = l; 20 *high = r; 21 } 22 23 void subarr(int arr[], int *low, int *high, int *sum){ 24 if(*low == *high){ //base case 25 *sum = arr[*low]; 26 return; 27 } 28 int l = *low, r = *high, s1, s2, s; 29 int m = (l + r) / 2; 30 int l1 = l, l2 = m + 1, r1 = m, r2 = r; 31 subarr(arr, &l1, &r1, &s1); //求左数组最大子数组 32 subarr(arr, &l2, &r2, &s2); //求右数组最大子数组 33 subcross(arr, &l, &m, &r, &s); //求跨中点最大子数组 34 //合并,先左再中后右,因为题目要求求第一个最大子数组,也就是最左边的一个 35 if(s1 >= s2 && s1 >= s){ 36 *low = l1; *high = r1; *sum = s1; 37 } 38 else if(s >= s1 && s >= s2){ 39 *low = l; *high = r; *sum = s; 40 } 41 else{ 42 *low = l2; *high = r2; *sum = s2; 43 } 44 } 45 46 int main(){ 47 int t, n, low, sum, high, i, j = 1; 48 scanf("%d", &t); //t表示测试的组数 49 while(t-- && scanf("%d", &n)){ //n表示每组测试的元素个数 50 i = 1; //用来标记下标,从1开始 51 while(n--) 52 scanf("%d", &a[i++]); 53 low = 1; //最左下标 54 high = i - 1; //最右下标 55 subarr(a, &low, &high, &sum); 56 printf("Case %d:\n%d %d %d\n", j++, sum, low, high); 57 if(t) putchar('\n'); 58 } 59 return 0; 60 }