题目链接: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; } }