hdu 1003 Max Sum 分治法

原题链接

思路: 将原数组递归分解为两个子数组,直到能求解出子解为止,再将答案合并。
 难点:产生数组的最大子序列只有以下三种情况:
  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 }

 

posted on 2014-02-10 14:34  长木Qiu  阅读(259)  评论(1编辑  收藏  举报