HDU 1003 Max Sum 分治法
思路: 将原数组递归分解为两个子数组,直到能求解出子解为止,再将答案合并。
难点:产生数组的最大子序列只有以下三种情况:
1.最大子序列为左子数组的最大子序列;
2.最大子序列为右子数组的最大子序列;
3.最大子序列为跨中点的最大子序列;(特殊情况)
依照以上三种情况分而治之即得解。
附ac代码
#include <stdio.h> int a[100001]; void subcross(int arr[], int *low, int *mid, int *high, int *sum){ int s = 0, maxl = -1000 - 1, maxr = -1000 - 1, l, r; for(int i = *mid; i >= *low; --i){ //以中点为基准,向左推进求最大左边界子序列 s += arr[i]; if(s >= maxl){ l = i; maxl = s; } } for(int i = *mid + 1, s = 0; i <= *high; ++i){ //以中点为基准,向右推进求最大右边界子序列 s += arr[i]; if(s > maxr){ r = i; maxr = s; } } *sum = maxl + maxr; //合并,传递参数 *low = l; *high = r; } void subarr(int arr[], int *low, int *high, int *sum){ if(*low == *high){ //base case *sum = arr[*low]; return; } int l = *low, r = *high, s1, s2, s; int m = (l + r) / 2; int l1 = l, l2 = m + 1, r1 = m, r2 = r; subarr(arr, &l1, &r1, &s1); //求左数组最大子数组 subarr(arr, &l2, &r2, &s2); //求右数组最大子数组 subcross(arr, &l, &m, &r, &s); //求跨中点最大子数组 //合并,先左再中后右,因为题目要求求第一个最大子数组,也就是最左边的一个 if(s1 >= s2 && s1 >= s){ *low = l1; *high = r1; *sum = s1; } else if(s >= s1 && s >= s2){ *low = l; *high = r; *sum = s; } else{ *low = l2; *high = r2; *sum = s2; } } int main(){ int t, n, low, sum, high, i, j = 1; scanf("%d", &t); //t表示测试的组数 while(t-- && scanf("%d", &n)){ //n表示每组测试的元素个数 i = 1; //用来标记下标,从1开始 while(n--) scanf("%d", &a[i++]); low = 1; //最左下标 high = i - 1; //最右下标 subarr(a, &low, &high, &sum); printf("Case %d:\n%d %d %d\n", j++, sum, low, high); if(t) putchar('\n'); } return 0; }