先说一下最大连续子段和。
dp可以o(n)地求出最大连续子段和。
若a[i]表示原来的数组,令dp[i]记录以第 i 个数结尾的最大连续子段和。
转移方程是dp[i]=max(dp[i-1]+a[i],a[i])
程序如下:
#pragma warning(disable:4996)
#include <cstdio>
#include <algorithm>
#define N 105
using namespace std;
int dp[N], a[N];
int main(){
int n;
while (scanf("%d", &n)){
for (int i = 1; i <= n; i++)scanf("%d", a + i);
dp[0] = 0;
for (int i = 1; i <= n; i++){
dp[i] = max(dp[i - 1] + a[i], a[i]);
}
//找到dp数组中的最大值便是所求最大连续子段和
int ans = dp[1];
for (int i = 2; i <= n; i++)ans = max(ans, dp[i]);
printf("%d\n", ans);
}
return 0;
}
POJ 1050 To the Max
题意:给一个 n*n 的矩阵,求出子矩阵中矩阵和最大值,矩阵和就是矩阵内所有数字之和。
思路:二维的最大连续子段和。方法是枚举两行,然后计算两行之间各列的列和,然后把列和当作一维的最大连续子段和来做。
#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int mp[105][105], col[105], dp[105];
int main(){
int n;
while (scanf("%d", &n) != EOF){
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++)scanf("%d", &mp[i][j]);
}
int ans = -1000000000;
//枚举行
for (int i = 1; i <= n; i++){
for (int j = i; j <= n; j++){
//计算行i,行j之间的各列分别的和
for (int k = 1; k <= n; k++){
col[k] = 0;
for (int r = i; r <= j; r++)col[k] += mp[r][k];
}
//计算出各列和之后按照一维的最大连续子段和做
dp[0] = 0;
for (int i = 1; i <= n; i++){
dp[i] = max(dp[i - 1] + col[i], col[i]);
}
for (int i = 1; i <= n; i++)ans = max(ans, dp[i]);
//一维的最大连续子段和可以简化如下:
/*int sum = 0;
for (int i = 1; i <= n; i++){
sum += col[i];
if (sum < 0)sum = 0;
ans = max(ans, sum);
}*/
}
}
printf("%d\n", ans);
}
return 0;
}
POJ 2479 Maximum sum
题意:给你一个数组,求两段不相交连续子段和的最大值,两段可以连续,可以不连续。
思路:dp1[i]表示以 i 结尾的最大连续子段和,dp2[i]表示以 i 开头的最大连续子段和。
然后呢,很容易想到的思路就是枚举第一段和第二段的分界点,然后把分界点前的dp1和分界点后面的dp2加起来,取最大值。
但是呢,枚举分界点前的dp1,再枚举分界点后的dp2复杂度总计是o(n^3)的,,肯定会T
这时候就得转转脑子了,其实我们并不需要枚举分界点,只要枚举dp1[i],分界点就是i了,然后在枚举i后面的dp2
复杂度是o(n^2)的,也会T。。
最后呢,我们可以注意到,每当我们枚举dp1[i]时呢,我们要把dp1[i]加上我们枚举的dp2的值,然后去和的最大值,
也就是找到i后面的dp2的最大值,。这样我们就可以先把dp2的最大值o(n)时间预处理出来。用mxa[i]存储i以及i之后的dp2的最大值。然后我们就要找dp1[i]+mxa[i+1]的最大值就好了
#pragma warning(disable:4996)
#include <cstdio>
#include <algorithm>
#define N 50005
using namespace std;
int dp1[N], dp2[N], a[N];
int mxa[N];
int main(){
int t; scanf("%d", &t);
while (t--){
int n; scanf("%d", &n);
for (int i = 1; i <= n; i++)scanf("%d", a + i);
//dp1[i]以i结尾
dp1[0] = 0;
for (int i = 1; i <= n; i++){
dp1[i] = max(dp1[i - 1] + a[i], a[i]);
}
//dp2[i]以i开头
dp2[n + 1] = 0;
for (int i = n; i >= 1; i--){
dp2[i] = max(dp2[i + 1] + a[i], a[i]);
}
mxa[n] = dp2[n];
for (int i = n - 1; i >= 1; i--)mxa[i] = max(mxa[i + 1], dp2[i]);
//枚举分界点,TLE
/*int ans = dp1[1] + dp2[n];
for (int i = 2; i < n; i++){
for (int j = 1; j <= i; j++){
for (int k = i + 1; k <= n; k++){
ans = max(ans, dp1[j] + dp2[k]);
}
}
}*/
int ans = dp1[1] + mxa[2];
for (int i = 2; i < n; i++){
ans = max(ans, dp1[i] + mxa[i + 1]);
}
printf("%d\n", ans);
}
return 0;
}