题目链接: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;
}
}
本文介绍了如何解决HDU 1231题——最大连续子序列。讨论了暴力求解和分治法两种策略,详细阐述了分治法的递归思想和在处理下标问题上的难点。同时,提到了C++函数返回多个数值的方法,如使用数组、指针或引用。
3648

被折叠的 条评论
为什么被折叠?



