题目:
http://acm.hdu.edu.cn/showproblem.php?pid=1003
题解:
最开始题目都没看懂,看了别人的博客才知道这道题是要求最大子序列和。
这里我先归纳了三种求解最大子序列和问题的算法,在最后给出该题的AC代码。
方法1:暴力法 ( O(n^2) )
直接遍历所有可能的情况。
int maxSubSequence1(int arr[], int n)
{
int max_sum = 0, sum;
for (int i = 0; i < n; ++i) {
sum = 0;
for (int j = i; j < n; ++j) {
sum += arr[j];
if (sum > max_sum)
max_sum = sum;
}
}
return max_sum;
}
方法2:分治法( O(n*logn) )
若将一个序列从中分为两半的话,该序列的和最大的子序列的位置不外乎三种情况——左边的序列中、右边的序列中、横跨两个序列,所以这里可使用分治法来解决。
int maxSubSequence2(int arr[], int left, int right)
{
if (left == right)
if (arr[left] > 0)
return arr[left];
else
return 0;
int mid = (left + right) >> 1;
// 获取左子序列中的最大子序列和
int maxLeftSum = maxSubSequence2(arr, left, mid);
// 获取右子序列中的最大子序列和
int maxRightSum = maxSubSequence2(arr, mid + 1, right);
// 获取横跨左右子序列的最大子序列之和
int maxLeftBorderSum = 0, leftBorderSum = 0;
for (int i = mid; i >= left; --i) {
leftBorderSum += arr[i];
if (leftBorderSum > maxLeftBorderSum)
maxLeftBorderSum = leftBorderSum;
}
int maxRightBorderSum = 0, rightBorderSum = 0;
for (int i = mid + 1; i <= right; ++i) {
rightBorderSum += arr[i];
if (rightBorderSum > maxRightBorderSum)
maxRightBorderSum = rightBorderSum;
}
// 从三者中选出最大子序列的和
return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum);
}
int max3(int a, int b, int c)
{
if (a > b)
return a > c ? a : c;
else
return b > c ? b : c;
}
方法3: 动态规划法 ( O(n) )
int maxSubSequence3(int arr[], int n)
{
int sum = 0, max_sum = 0;
for (int i = 0; i < n; ++i) {
sum += arr[i];
if (sum > max_sum)
max_sum = sum;
else if (sum < 0)
sum = 0;
}
return max_sum;
}
AC代码:
#include <iostream>
using namespace std;
int main()
{
//int maxSubSequence1(int arr[], int n);
//int maxSubSequence2(int arr[], int left, int right);
//int maxSubSequence3(int arr[], int n);
//int max3(int a, int b, int c);
int n_case;
cin >> n_case;
for (int j = 0; j < n_case; ++j) {
int n, val, start, end, sum = 0, max_sum = -3000, tmp = 1; // Damn 这个该死的max_sum!!!!!! 我之前初始值为0,结果一直AC不了
start = end = 1;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> val;
sum += val;
if (sum > max_sum) {
max_sum = sum;
start = tmp;
end = i+1;
}
if (sum < 0){
sum = 0;
tmp = i + 2;
}
}
// 5 1 -1 4 -5 3
printf("Case %d:\n", j + 1);
printf("%d %d %d\n", max_sum, start, end);
if (j < n_case - 1)
printf("\n");
}
return 0;
}