P1121环状最大两段子段和

P1121环状最大两段子段和

题目

image-20210307115607131

假定一个小白看这道题,一步步了解相关知识

最大子段和(DP,O(n))

状态dp[i]表示以A[i]作结尾的最大连续子序列和,求出dp数组的最大值即题解

dp[1] = a[1];	//边界条件
for(int i = 2; i <= n; ++i)
{
   
    dp[i] = max(dp[i - 1] + a[i], a[i]);	//状态转移方程
}
sort(dp + 1, dp + n + 1);	//找到dp数组的最大值
ans1 = dp[n];

模板题P1115

拓展题PAT1045

拓展题题解

环状最大子段和

a[n]a[1]相邻,取得的最大子段分两种情况

  • 最大子段没有跨过a[n]a[1],即和非环状最大子段和的结果是一样的,直接使用DP可解,得ans1
  • 最大子段跨过了a[n]a[1],此时,问题转化为求最小子段和min1,然后我们求整个序列的和sum,得ans2 = sum - min1

ans1ans2的最大值就是题解

有些初学者难以理解ans2 = sum - min1,它的前提条件是序列是一个环状,这个环上的数字的总和是确定的,我们从这个环上剔除和最小的子段,剩下子段的和自然就是最大子段和(这里,我们需要清楚,最大子段和最小子段只有一个可以跨过序列首和尾的,因为这个转折点只有一个),举个栗子

image-20210307151917191

这个序列的和sum = 9,最小序列(未跨)和是min = a[2] + a[3] = -7,那么最大序列(跨过)和就是ans2 = sum - min = 16 = a[4] + a[5] + a[1]

最小(负数)子段和(DP,O(n))

和求最大子段和类似,状态dp[i]表示以a[i]结尾的最小子段和,分两种情况求dp[i]

  • 如果dp[i - 1] > 0那么a[i]就自立门户,dp[i] = a[i]

  • 否则,就将a[i]接在a[i - 1]后面,dp[i] = a[i] + dp[i - 1]

    下面是利用最小子段和求环状最大子段和

dp[1] = a[1];	//边界条件
sum = a[1];
for(int i = 2; i <= n; ++i)
{
   
    dp[i] = min(a[i], dp[i - 1] + a[i]);	//状态转移方程
    sum += a[i];
}
sort(dp + 1, dp + n + 1);
if(dp[1] < 0)
	min1 = dp[1];	//找到dp数组最小值
else
    min1 = 0;
ans2 = sum - min1;	//求得ans2

cout << max(ans1, ans2);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值