最大连续和的不断优化过程

原创、转载请注明出处

给出一个长度为n的序列,求最大连续和

1、n3

#include<iostream>
using namespace std;

int f(int P[], int n)
{
    int ans = P[0];
    for(int i = 0; i < n; i ++)
    {
        for(int j = i; j < n; j ++)
        {
            int sum = 0;
            for(int k = i; k <= j; k ++)
            {
                sum += P[k];
                if(sum > ans)ans = sum;
            }
        }
    }
    return ans;
}

int main()
{
    int n;
    cin >> n;
    int P[1000],S[1000];
    for(int i = 0; i < n; i ++)
    {
        cin >> P[i];
    }
    cout << f(P, 0, n) << endl;
    return 0;
}

 

2、n2
记录、递推思想

int f(int P[], int S[], int n)
{
    S[0] = 0;
    int ans = P[1];
    for(int i = 1; i <= n; i ++)
    {
        S[i] = S[i-1] + P[i];//S[i]代表从P[1]到P[i]的和
    }
    for(int i = 1; i <= n; i ++)
    {
        for(int j = i; j <= n; j ++)
        {
            if((S[j] - S[i - 1]) > ans)
            {
                ans = maxS[j] - S[i - 1];
            }
        }
    }
    return ans;
}


int main()
{
    int n;
    cin >> n;
    int P[1000],S[1000];
    for(int i = 1; i <= n; i ++)
    {
        cin >> P[i];
    }
    cout << f(P, S, n) << endl;
    return 0;
}

 

3、nlogn

分治算法一般分为以下3个步骤:

划分问题:把问题的实例划分成子问题。

递归求解:递归解决子问题。

合并问题:合并子问题的解得到原问题的解。

 

最大连续和的分治算法:

1、把序列分成元素个数尽量相等的两半;2、分别求出完全位于左半或者完全位于右半的最佳序列;3、求出起点位于左半、终点位于右半的最大连续和序列,并和子问题的最优解比较。

#include<iostream>
using namespace std;

int f(int A[], int x, int y)//返回在[x,y)中的最大连续和
{
    if(x == y - 1)
    {
        return A[x];
    }
    int mid = x + (y - x) / 2, ans = A[x];
    ans = max(ans, f(A, x, mid));
    ans = max(ans, f(A, mid, y));
    int L = A[mid - 1],R = A[mid];
    for(int i = x; i < mid; i ++)
    {
        int sum = 0;
        for(int j = i; j < mid; j ++)
        {
            sum += A[j];
        }
        L = max(L, sum);
    }
    for(int i = mid; i < y; i ++)
    {
        int sum = 0;
        for(int j = i; j < y; j ++)
        {
            sum += A[j];
        }
        R = max(R, sum);
    }
    ans = max(ans, L + R);
    return ans;
}

int main()
{
    int n;
    cin >> n;
    int P[1000],S[1000];
    for(int i = 0; i < n; i ++)
    {
        cin >> P[i];
    }
    cout << f(P, 0, n) << endl;
    return 0;
}

该方法的2个细节:

1、左闭右开的“数组分割”。使得处理自然。

2、(x+y)/2和x+(y-x)/2。数学上等价,在计算机中,前者是朝零取整,后者是朝区间起点取整。

 

4、n

在O(n2)算法上稍作修改:当j确定时,“S[j]-S[i-1]最大”相当于“S[i-1]最小”,因此只需要扫描一次数组,维护“目前遇到过的最小S”即可。

#include<iostream>
using namespace std;

int f(int P[], int S[], int n)
{
    S[0] = 0;
    int ans = P[0];
    for(int i = 1; i <= n; i ++)
    {
        S[i] = S[i-1] + P[i];//代表从P[0]到P[i]所有元素的和
    }
    int minn = S[1];
    for(int i = 1; i <= n; i ++)
    {
        minn = min(minn, S[i - 1]);
        ans = max(ans, S[i] - minn);
    }
    return ans;
}


int main()
{
    int n;
    cin >> n;
    int P[1000],S[1000];
    for(int i = 1; i <= n; i ++)
    {
        cin >> P[i];
    }
    cout << f(P, S, n) << endl;
    return 0;
}

 

posted @ 2017-10-16 08:41  哲贤  阅读(242)  评论(0编辑  收藏  举报