最大字段和

题目

给定由 n 个 整 数 ( 可 能 有 负 数 ) 组 成 的 序 列 a 1 , a 2 , . . . , a n , 要 在 这 n 个 数 中 选 取 相 邻 的 一 段 a i , a i + 1 , . . . , a j ( 1 ≤ i ≤ j ≤ n ) , 使 其 和 最 大 , 输 出 最 大 的 和 。 当 所 有 整 数 均 为 负 整 数 时 , 定 义 最 大 字 段 和 为 0 。 n个整数(可能有负数)组成的序列a_1,a_2,...,a_n,要在这n个数中选取相邻的一段a_i,a_{i+1},...,aj(1\leq i \leq j \leq n),使其和最大,输出最大的和。当所有整数均为负整数时,定义最大字段和为0。 n()a1,a2,...,an,naiai+1,...,aj1ijn,使0
例如,当 { a 1 , a 2 , . . . , a 8 } \{a_1,a_2,...,a_8\} {a1,a2,...,a8} = {1,-3,7,8,-4,12,-10,6}时,最大字段和为23。令 b [ j ] = max ⁡ 1 ≤ i ≤ j { ∑ k = i j a [ k ] } ( 1 ≤ j ≤ n ) , b[j] =\max_{1 \leq i \leq j} \{ \sum_{k=i}^j a[k]\} (1 \leq j \leq n), b[j]=1ijmax{k=ija[k]}(1jn),则所求的最大字段和为:
max ⁡ 1 ≤ i ≤ j ≤ n { ∑ k = i j a [ k ] } = = max ⁡ 1 ≤ j ≤ n { max ⁡ 1 ≤ i ≤ j { ∑ k = i j a [ k ] } } = max ⁡ 1 ≤ j ≤ n { b [ j ] } \max_{1 \leq i \leq j \leq n} \{ \sum_{k=i}^j a[k]\} == \max_{1 \leq j \leq n} \{ \max_{1 \leq i \leq j} \{\sum_{k=i}^j a[k]\} \} = \max_{1 \leq j \leq n} \{ b[j]\} 1ijnmax{k=ija[k]}==1jnmax{1ijmax{k=ija[k]}}=1jnmax{b[j]}
其实上面定义看不懂并不影响理解,看懂下面的递归关系即可,上面写着只是为了显得更专业,好吧!我承认是课本的定义。

建立递归关系

b [ j − 1 ] > 0 时 , b [ j ] = b [ j − 1 ] + a [ j ] , 否 则 b [ j ] = a [ j ] 。 b[j-1]>0时,b[j] = b[j-1]+a[j],否则b[j] = a[j]。 b[j1]>0b[j]=b[j1]+a[j],b[j]=a[j]这句话还是十分简单的,要是前面的和大于0,那最大和一定要加上前面的正数。反之,若小于0则必须弃之。
b[j]状态转移方程为:
b [ j ] = max ⁡ { b [ j − 1 ] + a [ j ] , a [ j ] } , ( 1 ≤ j ≤ n ) b[j] =\max \{ b[j-1] + a[j],a[j] \}, (1 \leq j \leq n) b[j]=max{b[j1]+a[j],a[j]},(1jn)

代码

#include <stdio.h>

#define NUM 1001
int a[NUM];
int MaxSum(int n, int &besti, int &bestj)
{
	int sum=0; 
	int b=0;
	int begin = 0;//当b[i-1]小于等于0时,记录b[i]=a[i]的位置 
	for (int i = 1;i <= n;i++)
	{
		if (b>0) b+=a[i]; //状态转移方程 
		else {//当b<0时,更新到最新的位置 
			b=a[i];
			begin = i;//开始位置 
		}
		if (b>sum) 
		{
			sum = b; //更新最优值 
			besti = begin; 
			bestj = i;
		}
	}
	return sum;
}

int main() 
{
	int n;
	int besti, bestj;
	while (scanf("%d", &n) && n) 
	{
		besti = 0; //初始化开头 
		bestj = 0; //初始化结尾 
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		printf("%d\n", MaxSum(n, besti, bestj));//输出最优值 
		printf("From %d to %d\n", besti, bestj);//输出最优解 
	}
	return 0;
}

输入

8
1 -3 7 8 -4 12 -10 6
0

输出

23
From 3 to 6

总结

最大子矩阵和问题是最大字段和问题的推广,首先在这埋下一个坑,日后若遇到在加以学习吧!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值