[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代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#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,效率还没有上面的高:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#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;
}

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#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 @   纸牌  阅读(135)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示