最大字段和的改进-最接近0或某一其他固定值的字段和(习题10)

      一、对于最接近0的字段和求解

1、最接近0就相当于字段和的绝对值最小,此时问题等价于求绝对值最下的字段和。针对此,可以设置一个绝对值结构体,结构如下:

struct absVal {
    float value; //绝对值
    bool flag;   //标志位,true表示为非负数,否则为负数
};

  这样,可以将最简单的扫描算法改写成如下:

简单法求最接近0的字段和
float maxSum_easy(int n, int* a, int& besti, int& bestj) //最简单的方法,复杂度为O(n^3)
{
    int i = 0, j = 0, k = 0, sum = 0,sum_t = 0;
    absVal maxSoFar;
    if (a[0]>0)
    {
        maxSoFar.value = a[0];
        maxSoFar.flag = true;
    }
    else
    {
        maxSoFar.value = -a[0];
        maxSoFar.flag = false;
    }

    for (i = 0; i < n; ++i)
        for ( j = i; j < n; ++j)
        {
            sum = 0;
            for (k = i; k<=j; ++k)
                sum += *(a+k);
            sum_t = abs(sum);
            if (sum_t < maxSoFar.value)
            {
                maxSoFar.value = sum_t;
                if (sum_t != sum)
                    maxSoFar.flag = false;
                else
                    maxSoFar.flag = true;
                besti = i;
                bestj = j;
            }
        }
    if (maxSoFar.flag)
        return maxSoFar.value;
    else
        return -maxSoFar.value;
}

  同样可以改写另外两种O(n2)的算法,这里改进动态规划的算法如下:

动态规划方法求解最接近0字段和
struct absVal maxSum_sm(int* a, int n) //扫描算法,时间复杂度为O(n)
{
    absVal maxSoFar, maxendinghere, temp, absa;
    int i =0;

    //赋初值
    if (a[0] >= 0)
    {
        maxSoFar.value = a[0];
        maxSoFar.flag = true;
        maxendinghere.value = a[0];
        maxendinghere.flag = true;
    }
    else
    {
        maxSoFar.value = -a[0];
        maxSoFar.flag = false;
        maxendinghere.value = -a[0];
        maxendinghere.flag = false;
    }
    //从1->n-1依次扫描
    for (i = 1; i < n; ++i)
    {
        //求每一个元素的绝对值
        if (a[i] >= 0)
        {
            absa.value = a[i];
            absa.flag = true;
        }
        else
        {
            absa.value = -a[i];
            absa.flag = false;
        }

        //求结束位置为i的最接近0的字段和
        if (maxendinghere.flag && absa.flag || !maxendinghere.flag && !absa.flag)
        {
             temp.value = maxendinghere.value + absa.value;
             temp.flag = absa.flag;

        }
        else if(maxendinghere.value >= absa.value)
        {
            temp.value = maxendinghere.value - absa.value;
            temp.flag = maxendinghere.flag;
        }
        else
        {
            temp.value = absa.value - maxendinghere.value;
            temp.flag = absa.flag;
        }
        if (temp.value < absa.value)
        {
            maxendinghere.value = temp.value;
            maxendinghere.flag = temp.flag;
        }
        else
        {
            maxendinghere.value = absa.value;
            maxendinghere.flag = absa.flag;
        }
        if (maxendinghere.value < maxSoFar.value)
            maxSoFar = maxendinghere;
    }
    return maxSoFar;
}

2、课本上所给的答案并不是如此做的,而是设置一个累加数组cum,使得cum[i]=x[0]+...+x[i]。则sum(x[l..u])=cum[u]-cum[l-1],通过定位cum中最接近的两个元素来找出和最接近0的子向量和,而这可以通过排序数组,在O(nlogn)时间内完成。任何能够解决该问题的算法都能用于解决元素“唯一性”问题。 

 二、对于最接近某一个值v的字段和求解方法

类似于最接近0的方法求解,即求与v绝对值差的绝对值最小的字段和,可以同样实现之。

posted @ 2013-04-17 15:19  busyfruit  阅读(357)  评论(0编辑  收藏  举报