POJ 2479 Maximum sum (2593)

Description

Given a set of n integers: A={a1, a2,..., an}, we define a function d(A) as below:
Your task is to calculate d(A).

Input

The input consists of T(<=30) test cases. The number of test cases (T) is given in the first line of the input. 
Each test case contains two lines. The first line is an integer n(2<=n<=50000). The second line contains n integers: a1, a2, ..., an. (|ai| <= 10000).There is an empty line after each case.

Output

Print exactly one line for each test case. The line should contain the integer d(A).

Sample Input

1

10
1 -1 2 2 3 -3 4 -4 5 -5

Sample Output

13
 
 
题意:给出一段数字,要求出其中两个不交叉的子段的和的最大值。
思路:用DP的方式,从前往后扫一遍求出到每一点的最大和子段的和,然后从后往前扫一遍。
先贴一段好理解的代码,这个代码很好理解但多了几个循环
#include <iostream>
using namespace std;

int Data[50001];//元数据
int x[50001];//从前往后经过每一点的最大sum值
int y[50001];//从后往前经过每一点的最大sum值

int main()
{
	//输入case次数
	int time = 0;
	cin>>time;

	int num = 0;
	int sum = 0;
	//初始化数组
	memset(x, 0, sizeof(x));
	memset(y, 0, sizeof(y));

	while (time--)
	{
		//输入元数据个数
		cin>>num;

		//特例,当元数据只有2个时直接求和
		if (num == 2)
		{
			cin>>Data[0]>>Data[1];
			sum = Data[0] + Data[1];
			cout<<sum<<endl;
			continue;
		}

		//输入元数据并求 从前往后数,到达每一点 并包括该点 的子片段的最大和
		for (int i=0; i<num; i++)
		{
			cin>>Data[i];

			if (i == 0)
			{
				x[i] = Data[i];
			}
			else 
			{
				if (x[i-1] > 0)
				{
					x[i] = x[i-1] + Data[i];
				}
				else
				{
					x[i] = Data[i];
				}
			}
		}

		//从后往前数,到达每一点 并包括该点 的子片段的最大和
		for (int j=(num-1); j>=0; j--)
		{
			if (j == (num - 1))
			{
				y[j] = Data[j];
			}
			else
			{
				if (y[j + 1] > 0)
				{
					y[j] = y[j + 1] + Data[j];
				}
				else
				{
					y[j] = Data[j];
				}
			}
		}

		//无论从前往后还是从后往前,我们都要找到对于起点到该点的最大“子片段”和
		for (int n=1; n<num; n++)
		{
			if (x[n] < x[n-1])
				x[n] = x[n-1];

			if (y[num - n - 1] < y[num - n])
				y[num - n - 1] = y[num - n];
		}

		//我们计算最终对于每一点所能求得的最大和
		for (int k=0; k<(num-1); k++)
		{
			if ((x[k] + y[k+1]) > sum)
				sum = (x[k] + y[k+1]);
		}

		cout<<sum<<endl;
	}
	return 0;
}

上述代码时间上还有优化的地方,特别要注意在for循环中的计算能少则少不然以超过o(n)的复杂度很容易超时
下面这段代码经过改良,值得一提的是用C++流操作时会超时,而用C的scanf则不会。
 
#include <iostream>
#include <stdio.h>
using namespace std;
#define MIN -0xfffffff


int Data[50001];//元数据
int x[50001];//从前往后经过每一点的最大sum值


int main()
{
	//输入case次数
	int time = 0;
	scanf("%d", &time);
	//cin>>time;


	int num = 0;
	
	//初始化数组


	while (time--)
	{
		//输入元数据个数
		//cin>>num;
		scanf("%d", &num);
		int sum = 0;
		int temp = MIN;
		int out = MIN;


		//输入元数据并求 从前往后数,到达每一点 并包括该点 的子片段的最大和
		for (int i=1; i<=num; i++)
		{
			//cin>>Data[i];
			scanf("%d", &Data[i]);
			sum += Data[i];
			if (sum > temp)
			temp = sum;
			x[i] = temp;
			if (sum < 0)//这一步的判断使得之前超时的部分得以简化,减少了一轮for
				sum = 0;
		}
		temp = MIN;
		sum = 0;
		//从后往前数,到达每一点 并包括该点 的子片段的最大和
		for (int j=num; j>=2; j--)
		{
			sum += Data[j];
			if (sum > temp)
				temp = sum;
			if (x[j - 1] + temp > out)
			{
				out = x[j - 1] + temp;
			}
			if (sum < 0)
				sum = 0;
		}
		printf("%d\n", out);
		//cout<<out<<endl;
	}
	return 0;
}

 
2593和这个一样,结束的方式不一样而已
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值