文章目录
- 问题描述
- 分治法
- 动态规划法
问题描述
最大子段和问题;
洛谷P1115.最大子段和
分治法
利用归并排序的方法,但是由于是算最大子段和所以,并不能将它变成有序的,左边和右边的最大子段和通过调用函数,而中间的要算左边最大,右边最大加起来才是中间的最大子段和
最后返回左,右, 中的最大值
#include <iostream>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;const int N = 100010;int a[N], n;int max_subarray_sum(int l, int r) {if (l >= r) return a[l];int mid = l + r >> 1;int left_max = max_subarray_sum(l, mid);int right_max = max_subarray_sum(mid + 1, r);int left_border_max = 0, right_border_max = 0;int sum = 0;for (int i = mid; i >= l; i--) {sum += a[i];left_border_max = max(left_border_max, sum);}sum = 0;for (int i = mid + 1; i <= r; i++) {sum += a[i];right_border_max = max(right_border_max, sum);}int combined_max = left_border_max + right_border_max;return max({left_max, right_max, combined_max});
}signed main() {scanf("%lld", &n);for (int i = 0; i < n; i++) scanf("%lld", &a[i]);printf("%lld\n", max_subarray_sum(0, n - 1));return 0;
}
动态规划法
#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 200010;int dp[N], a[N], n;int main()
{scanf("%d", &n);for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);int res = -1e8;for (int i = 1; i <= n; i ++){dp[i] = max(a[i], dp[i - 1] + a[i]);res = max(dp[i], res);}printf("%d", res);return 0;
}
由于状态计算只用到了数组的上一个元素,所以可以用一个变量表示滚动数组,这样就不用开一个数组了
#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 200010;int a[N], n, dp;int main()
{scanf("%d", &n);for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);int res = -1e8;dp = 0;for (int i = 1; i <= n; i ++){dp = max(a[i], dp + a[i]);res = max(res, dp);}printf("%d", res);return 0;
}