给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大。
暴力解法:
int n;
int a[200000 + 10];
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
int ans = -1;
for(int i = 1; i <= n; i++){
for(int j = i; j <= n; j++){
int summ = 0;
for(int k = i; k <= j; k++){
summ += a[k];
}
ans = max(summ, ans);
}
}
cout << ans;
return 0;
}
前缀和优化:
int n;
int a[200000 + 10];
int s[200000 + 10];
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
int ans = -1;
for(int i = 1; i <= n; i++){
for(int j = i; j <= n; j++){
ans = max(s[j] - s[i - 1], ans);
}
}
cout << ans;
return 0;
}
动规:
第一个数为一个有效序列
如果一个数加上上一个有效序列得到的结果比这个数大,那么该数也属于这个有效序列。
如果一个数加上上一个有效序列得到的结果比这个数小,那么这个数单独成为一个新的有效序列
状态转移方程:f[i]=max(f[i−1]+a[i],a[i])f[i] = max(f[i - 1] + a[i], a[i])f[i]=max(f[i−1]+a[i],a[i])
在计算过程中记录max就好了
#include <iostream>
#include <cstdio>
#include <algorithm>
#define endl "\n"
using namespace std;
int n;
int a[200000 + 10];
int f[200000 + 10];
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
int ans = -100000;
for(int i = 1; i <= n; i++){
f[i] = max(f[i - 1] + a[i], a[i]);
ans = max(f[i], ans);
}
cout << ans;
return 0;
}
贪心
如果前面一段数的和是负数了,那么下一个数也没有必要需要前面的数来构成最大值了,因为会变小
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int n;
int a[200009];
int sum;
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
for(int i = 1; i <= n; i++){
if(sum < 0) sum = 0;
sum += a[i];
ans = max (ans, sum);
}
cout << ans;
return 0;
}
这篇博客介绍了如何解决寻找序列中连续子段最大和的问题,分别展示了暴力求解、前缀和优化、动态规划和贪心算法四种方法。动态规划方法通过状态转移方程f[i]=max(f[i−1]+a[i],a[i])实现,而贪心算法则根据当前数与前缀和的关系判断是否加入序列。
2433

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



