1231:最大连续子序列

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1231

方法:暴力、分治

思路:首先用暴力法求解,遍历所有的下标组合,然后求所有这些下标组合的和,求出最大的即可。第二种方法是分治法,最大和子序列一定会出现在左半部分、右半部分和跨越中间点的部分,因此可以分成三部分考虑,这样就可以递归求解了。详细代码过程见注释,算法分析见算法导论。

另外,c++函数如果要返回多个数值,一个是返回数组,而是传参传入数据指针,或者传入引用,引用的作用类似于指针。

难点:对于分治法递归的理解。如何在分治法中处理下标问题。

#include<iostream>
#include<climits>
using namespace std;
const int MAX = 10000;
/*
* 方法一:暴力解法,直接搜索所有的可能下标配对,计算两个下标之间的和并比较大小,找出最大的那个
*/
int GetSum(int *array,int start,int end)
{
    int sum = 0;
    for(int i = start;i <= end;i++)
    {
        sum += array[i];
    }
    return sum;
}
int FindMaxSubSuquenceV1(int *array,int n,int &low,int &high)
{
    int max = INT_MIN;
    for(int i = 0;i < n;i++)
    {
        for(int j = i;j < n;j++)
        {
            int temp = GetSum(array,i,j);
            if(max < temp)
            {
                max = temp;
                low = array[i];
                high = array[j];
            }
        }
    }
    return max;
}
/*
* 方法二:分治法
*/
int FindCrossMaxSum(int *array,int low,int high,int &markLow,int &highMark)//求跨越重点的最大和函数
{
    int leftSum = INT_MIN;
    int rightSum = INT_MIN;
    int tempSum = 0;
    int mid = (high+low)/2;
    for(int i = mid;i >= low;i--)
    {
        tempSum += array[i];
        if(tempSum > leftSum)
        {
            leftSum = tempSum;
            markLow = array[i];
        }
    }
    tempSum = 0; //注意这里需要清一下零才能计算右边的最大和
    for(int i = mid+1;i <= high;i++)
    {
        tempSum += array[i];
        if(tempSum > rightSum)
        {
            rightSum = tempSum;
            highMark = array[i];
        }
    }
    return rightSum+leftSum;
}
int FindMaxSubSuquenceV2(int *array,int low,int high,int &markLow,int &markHigh)//递归求解最大和
{
    if(low == high) //如果只有一个数,则直接返回该数
    {
        markHigh = array[high];
        markLow = array[low];
        return array[low];
    }
    else
    {
        int leftlow,lefthigh,rightlow,righthigh,midlow,midhigh;
        int mid = (low+high)/2;
        int leftMaxSum = FindMaxSubSuquenceV2(array,low,mid,leftlow,lefthigh);
        int rightMaxSum = FindMaxSubSuquenceV2(array,mid+1,high,rightlow,righthigh);
        int crossMaxSum = FindCrossMaxSum(array,low,high,midlow,midhigh);
        if(leftMaxSum >= rightMaxSum && leftMaxSum >= crossMaxSum) //寻找右半部分、左半部分、跨中点三种和求最大值
        {
            markLow = leftlow;
            markHigh = lefthigh;
            return leftMaxSum;
        }

        else if(rightMaxSum >= leftMaxSum && rightMaxSum >= crossMaxSum)
        {
            markLow = rightlow;
            markHigh = righthigh;
            return rightMaxSum;
        }
        else
        {
            markLow = midlow;
            markHigh = midhigh;
            return crossMaxSum;

        }
    }
}

int main()
{
    int array[MAX] = {0};
    int low,high;
    int n;
    while(cin>>n)
    {
        int flag = 0;
        if(n == 0) break;
        for(int i = 0;i < n;i++)
        {
            cin>>array[i];
            if(array[i] < 0)
                flag++;
        }
        //cout<<flag<<endl;
        if(flag == n)
        {
            cout<<"0"<<" "<<array[0]<<" "<<array[n-1]<<endl;
            continue;
        }
        //int ans = FindMaxSubSuquenceV1(array,n,low,high);
        int ans = FindMaxSubSuquenceV2(array,0,n-1,low,high);
        //int ans = maxSum(array,0,n-1);
        cout<<ans<<" "<<low<<" "<<high<<endl;
    }

}



你可能感兴趣的:(1231:最大连续子序列)