POJ 1050 To the Max && POJ 2479 Maximum sum(DP最大连续子段和)

先说一下最大连续子段和。

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值