基本解题思路:动态规划,不考虑穷举,分治。

根据网上,状态转移方程是:MaxSum[i] = Max{ MaxSum[i-1] + A[i], A[i]}

翻译公式:到当前位置i 时,最大子序列和为: i-1 时最大子序列和 + 当前数 与 当前数 相比中大的那个。

(翻译的不清楚也就说明对问题了解不够)

这个状态转移公式即为解决问题,划分问题的方法。这样划分子问题对不对。。。。。不去证明。

从理解的角度上来说,对于一个数串,把它分为maxsum(a0…ai-1),ai。那么对于i,来说,最大子序列和的值即为,maxsum(ai-1)+ ai 或者 ai。

对于初始状态 i = 0; 时, maxsum = a0; 当 i=1 时 maxsum = maxsum(a0) + ai or ai。

 

废话这么多,也没证明什么出来,反正从理解公式上来说,这个状态转移公式提出了问题的解决办法。

 

实际操作上来说。有三个变量:sum maxsum i.

 

对于数组A, 从0 开始计算sum, sum = a0 + … + , maxsum 设置为-10010, i 从 0开始计算。

当sum > maxsum 时, maxsum = sum.

若sum < 0 , sum = 0 及说明目前的sum+ai, 肯定小于 ai, 即重新开始计算子串值。

将maxsum设为一个很大的负数的好处是就不用考虑数组a全为负数的情况。

 

对于最大值的子串的索引,可以用三个变量表示,start temp end,初始值全设为0,

如果sum > max  start = temp, end = i 

如果sum < 0  sum = 0  temp = i+1

由于结果比实际的索引大1 则需要对start end 加一。

参考代码

http://blog.csdn.net/worker90/article/details/6649897

 

下面是我写的代码。

#include <stdio.h>
#include <stdlib.h>


void max_sum(int *a, int solution[3], int N)
{
    int sum, i, j, maxsum;
    sum = 0;
    j = 0;
    int start, temp, end;
    maxsum = -10001;
    temp = 0;
    start = 0; end = 0;


    for (i = 0; i < N; i++) {
        sum += a[i];
        if (sum > maxsum) {
            maxsum = sum;
            start = temp;
            end = i ;
        }
        if (sum < 0) {
            sum = 0;
            temp = i + 1;
        }
    }
    solution[0] = maxsum;
    solution[1] = start +1;
    solution[2] = end + 1;

}

int main(void)
{
    int T, N;
    int a[100002], solution[3];
    int i;
    int j = 1;
    scanf("%d", &T);

    while (T > 0) {
        scanf("%d", &N);
        for (i = 0; i < N; i++) {
            a[i] = 0;
            scanf("%d", &a[i]);
        }

        max_sum(a, solution, N);
        printf("Case %d:\n", j);

        printf("%d %d %d\n", solution[0], solution[1], solution[2]);
        if (T > 1) {
            printf("\n");
        }
        j++;
        T--;
    }
    system("pause");
}

 

posted on 2016-07-17 19:37  混沌奇迹  阅读(287)  评论(0编辑  收藏  举报