Max Sum(最大子段和问题)

最大子段和:给定一个序列(元素可正可负),找出其子序列中元素和最大的值。

我们用dp(i)表示序列中以元素ans(i)结尾的序列的最大子段和,那么有:dp(i)=max(dp(i-1)+ans(i),ans(i));

#define INF 999999999
int solve(int ans[],int n)  
{  
    dp[0]=0;  
    int nmax=-INF;  
    for(int i=1;i<=n;i++)  
    {  
        dp[i]=max(dp[i-1]+ans[i],ans[i]);  
        nmax=max(nmax,dp[i]);  
    }  
    return nmax;  
}  


首先来看一道比较基础的最大子段和问题--HDU1003   Max Sum:

题目大意:给定一个序列,让求出此序列的最大子段和,并输出该子序列在原序列中的位置。

这里我们用变量sum来代替dp()数组,如果sum+a(i)=a(i),则只需更新sum的值;

代码如下:

#include 
#include 
using namespace std;
const int MAX=100005;
int main()
{
    int t,n,a[MAX],i;
    int T=0;
    while(scanf("%d",&t)!=-1)
      while(t--)
      {
          T++;
          scanf("%d",&n);
          int sum,max,head,tail,x;
          for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
          head=tail=x=1;
          max=sum=a[1];
          for(i=2;i<=n;i++)
          {
              if(sum+a[i]max)
              {
                  max=sum;
                  tail=i;
                  head=x;
              }

          }
          printf("Case %d:\n%d %d %d\n",T,max,head,tail);
          if(t) printf("\n");
      }
      return 0;
}


 

下面看POJ上一道最大子段和的问题    http://poj.org/problem?id=2479

题目大意:给你一个序列,求出这个序列中两个互不相交的子序列的和的最大值。

由于找两个互不相交的子序列,我们可以从左到右,再从右到左分别求出这个序列的dp()值,然后在这些dp()值互不重叠的情况下分别找出两个dp()的最大值相加即可。具体实现呢,可以简化这个思想,只需找出一个dp()值就可以,我们找出正序的dp()数组,对于逆序的情况呢,用一层for循环,每一次循环,我们用一个变量temp来存放从i到n的这些子序列中的最大子段和,然后和1到i的最大子段和相加,这样经历n次循环之后我们就找到了所要求的值。

代码如下:

#include 
#include 
#include 
#define INF -999999999
using namespace std;
int ans[50050],dp[50050];
int main()
{
    int t,n,i;
    cin>>t;
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d",&n);
        for(i=1;i<=n;i++)
          scanf("%d",&ans[i]);
        for(i=1;i<=n;i++)
          dp[i]=max(dp[i-1]+ans[i],ans[i]);
        int temp=0;
        int solve=INF,nmax=INF;
        for(i=n;i>1;i--)
        {
            temp=max(temp+ans[i],ans[i]);
            nmax=max(nmax,temp);
            if(solve


 

你可能感兴趣的:(DP)