先说一下最大连续子段和。
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; }