[DP]最大连续子序列-hdu 1231

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1231

算法参考:http://blog.163.com/wuguojin03@126/blog/static/17154113120109510946717/

状态:dp[i]:以i为结尾的最大连续序列和
初始状态:dp[i]=a[i]
状态转移:dp[i]=max{dp[i-1]+a[i],a[i]}
要求最大的,只需从dp[i]找出最大值就行了

以本题输入样例 “ -2 11 -4 13 -5 -2 ” 为例:

序号:  0   1   2   3   4   5
 a[]: -2  11  -4  13  -5  -2
dp[]: -2  11   7  20  15  13

观察dp[],终点即为 max:20,起点则为从max往前找最后一个不为负的数,即11

AC代码:

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;

const int N=10010;
int a[N],dp[N];

int main()
{
    int n;
    while(cin>>n && n){
        int s=0,e=0;
        for (int i = 0; i < n; ++i){
            cin>>a[i];
            dp[i]=a[i];
        }

        for(int i=1;i<n;++i){
            dp[i]=max( dp[i-1]+a[i] , a[i] );
        }

        //查找最大和及终点
        int mymax=-1;
        for (int i = 0; i < n; ++i){
            if(mymax<dp[i]){
                mymax=dp[i];
                e=i;
            }
        }
        //查找起点
        for(int i=e;i>=0;--i)
            if(dp[i]<0){
                s=i+1;
                break;
            }
        if(mymax<0)cout<<"0 "<<dp[0]<<" "<<dp[n-1]<<endl;
        else cout<<mymax<<" "<<a[s]<<" "<<a[e]<<endl;
    }
    return 0;
}

  

一年后,偶遇此题又做一遍,用的是双dp,效率还没有上面的高:

#include <algorithm>
#include <cstdio>
using namespace std;

const int MAXN=10000+5;

int a[MAXN],dp_l[MAXN],dp_r[MAXN];
int n;

int main()
{
	while(scanf("%d",&n)&&n>0)	{
		for(int i=0;i<n;++i){
			scanf("%d",&a[i]);
		}

		dp_l[0]=a[0];
		dp_r[n-1]=a[n-1];
		int ans=a[0],start=0,end=n-1;
		for(int i=1;i<n;++i){
			dp_l[i]=max(a[i],a[i]+dp_l[i-1]);
			if(dp_l[i]>ans){
				ans=dp_l[i];
				end=i;
			}
		}
		ans=a[0];
		for(int i=n-2;i>=0;--i){
			dp_r[i]=max(a[i],a[i]+dp_r[i+1]);
			if(dp_r[i]>=ans){
				ans=dp_r[i];
				start=i;
			}
		}
		
		if(ans<0){
			ans=0;start=0;end=n-1;
		}
		printf("%d %d %d\n",ans,a[start],a[end] );
	}
	return 0;
}

 

还有一种方法,也挺快,不过不是用的动态规划:

#include <algorithm>
#include <cstdio>
using namespace std;

const int MAXN=10000+5;

int a[MAXN],dp_l[MAXN],dp_r[MAXN];
int n;

int main()
{
	while(scanf("%d",&n)&&n>0)	{
		for(int i=0;i<n;++i){
			scanf("%d",&a[i]);
		}
		int start=0,end=n-1,left,ans=a[0],sum=0;
		for(int i=0;i<n;++i){
			if(sum<0) { //如果前几项和小于0,就重新开始记录
     			sum=0;
     			left=i; //刷新临时起点
     		}
     		sum+=a[i];        		
     		if(sum>ans){ //如果现在的sum大于原来的max,刷新数据
     			ans=sum;
     			start=left;
     			end=i;
     		}
		}
		
		if(ans<0){
			ans=0;start=0;end=n-1;
		}
		printf("%d %d %d\n",ans,a[start],a[end] );
	}
	return 0;
}

  

posted @ 2015-01-25 11:23  纸牌  阅读(133)  评论(0编辑  收藏  举报