hdu 1231 最大连续子序列

这道题是学校寒假div1上的题目。这道题当时并没有做出来,并且之后卡了很久,因此特意在这里总结一下问题。

算法一:

这个算法是我参考书上的归并算法写的。

首先我想着重说的是第十二行程序执行顺序的问题。

我原先的理解是先运行逗号左边的内容,再运行逗号右边的内容,后来发现这是不正确的。

经过测试程序先递归执行了程序右边的函数,因此得到的序号数比较大;正是由于这个原因,当遇到相同的最大值时,得到的下标总是最小的(确保29,36行运算符为>=)。

除此之外,我这道题存在的问题就是对递归归并算法不熟悉,搞不清执行的情况,因而导致逻辑出了问题,后来通过加maxsum 变量暂存目前最大值来解决左右区间得到最大值但互不知情的情况,这样就实现了正确更新左右序号。

 1 #include <cstdio>
 2 #include <iostream>
 3 using namespace std;
 4 int lefts,rights;
 5  long long A[10000 + 100];
 6 int maxsum = 0;
 7  long long  max_sum( long long *A,int x,int y){
 8     long long v,L,R,maxs;
 9     if(y-x==1)
10         return A[x];
11     int m=x+ (y-x)/2;
12     maxs = max(max_sum(A,x,m),max_sum(A,m,y));
13     v=0;
14     int l=m-1,r=m;
15     L=A[m-1];
16     for(int i=m-1;i>=x;i--){
17         long long  t= (v+=A[i]);
18         if(t>=L)l=i;
19         L=max(L,t);
20     }
21     v =0;
22     R=A[m];
23     for(int i=m;i<y;i++){
24         long long t= (v+=A[i]);
25         if(t>R)r=i;
26         R=max(R,t);
27     }
28     if(L+R>maxs){
29         if(L+R>=maxsum){
30             maxsum=L+R;
31             lefts=l;rights=r;
32         }
33         return L+R;
34     }
35     else{
36         if(maxs>=maxsum){
37             maxsum=maxs;
38             if(y-m==1&& maxs==A[m])
39                 rights=lefts=m;
40             else if(m-x==1&& maxs==A[x])
41                 lefts=rights=x;
42         }
43         return maxs;
44     }
45 }
46 int main(){
47     int n;
48     while(scanf("%d",&n)==1&&n){
49         maxsum = -1;
50         lefts=0,rights=n-1;
51         int fu=0;
52         for(int i=0;i<n;i++){
53             scanf("%lld",&A[i]);
54             if(A[i]<0)fu++;
55         }
56         if(fu!=n){
57             long long m=max_sum(A,0,n);
58             printf("%lld %lld %lld\n",m,A[lefts],A[rights]);
59         }
60         else
61             printf("0 %lld %lld\n",A[0],A[n-1]);
62     }
63     return 0;
64 } 

算法二:

这道题是从我女朋友那里搞来的算法,自己一开始理解起来比较困难。但经过了较长时间的思考推理,大概理解了这个算法。不得不说这个算法比我自己用的算法简洁多了。

但是我感觉不是思路很好想,并运行耗时更多(不知道为什么这个在OJ上 提交运行时间会不稳定,一次超时,再提交就AC了)。

对于这道题为什么可以这样写,我想根据sum值讨论一下。

1.假设任意处sum>=0.

假设以上图形代表最优解范围起点的两种可能性,一种是开始于a点,一种是开始于b点。假设从b点开始,因为sum>=0恒成立,所以A范围内数字大于等于0,所以A+B>=B,又因题目要求序号尽量小,所以我们的最优解范围是开始于a点。

2.假设存在一段sum<0

如图所示,假设B区域sum值都为负(即都为负数),假设最优解开始于a点,因为A+B<0,所以A+B+C区域的sum值一定小于C,所以最优解一定开始于c点。

综上,我们可以写出下面的代码

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int main()
 6 {
 7     int t;
 8     while(cin >> t &&t)
 9     {
10         int a[100005];
11         int  ans = -100000, sum = 0, fir = 0, la = 0, q = 0;
12         for(int i = 0; i < t; i++)
13             cin >> a[i];
14         for(int i = 0; i < t; i++)
15         {
16             if(sum < 0) {sum = a[i];q = i;}
17             else sum += a[i];
18             if(sum > ans)
19             {
20                 ans = sum;
21                 la = i;
22                 fir = q;
23             }
24         }
25         if(ans < 0) {ans = 0; fir = 0; la = t-1;}
26         printf("%d %d %d\n", ans, a[fir], a[la]);
27     }
28     return 0;
29 }

目前只能理解到这个程度,如有不当之处还望指教。

时间: 2024-10-24 20:20:02

hdu 1231 最大连续子序列的相关文章

HDU 1231 最大连续子序列 DP题解

典型的DP题目,增加一个额外要求,输出子序列的开始和结尾的数值. 增加一个记录方法,nothing special. 记录最终ans的时候,同时记录开始和结尾下标: 更新当前最大值sum的时候,更新开始节点. const int MAX_N = 10001; long long arr[MAX_N]; int N, sta, end; long long getMaxSubs() { long long sum = 0, ans = LLONG_MIN; int ts = 0; for (int

[ACM] hdu 1231 最大连续子序列 (动规复习)

最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 17687    Accepted Submission(s): 7828 Problem Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j

HDU 1231 最大连续子序列 --- 入门DP

HDU 1231 题目大意以及解题思路见: HDU 1003题解,此题和HDU 1003只是记录的信息不同,处理完全相同. /* HDU 1231 最大连续子序列 --- 入门DP */ #include <cstdio> #include <cstring> int dp[10005]; int main() { #ifdef _LOCAL freopen("D:\\input.txt", "r", stdin); #endif int n

HDU 1231——最大连续子序列(DP)

最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 18603    Accepted Submission(s): 8268 Problem Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j

HDU 1231 最大连续子序列:水dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1231 题意: 给你一个整数序列,求连续子序列元素之和最大,并输出该序列的首尾元素(若不唯一,输出首坐标最小的:首坐标相同输出尾坐标最小的). 题解: O(N)做法. 定义sum为当前坐标i之前某一段元素[x,i-1]之和. 三种情况: (1)sum > 0:说明之前的和对答案有贡献,更新sum += a[i],tail = a. (2)sum < 0:前面的答案是拖后腿的...还不如从a[i]重新

hdu 1231 最大连续子序列(DP)

最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 21166    Accepted Submission(s): 9387 Problem Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j

DP专题训练之HDU 1231 最大连续子序列

Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K.最大连续子序列是所有连续子序列中元素和最大的一个, 例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和 为20. 在今年的数据结构考卷中,要求编写程序得到最大和,现在增加一个要求,即还需要输出该 子序列的第一个和最后一个元素. In

hdu 1231 最大连续子序列 DP

最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 20633    Accepted Submission(s): 9151 Problem Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j

HDU 1231 最大连续子序列 (动规)

最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 18316    Accepted Submission(s): 8127 Problem Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j

hdu 1231最大连续子序列 动态规划

动态转移方程dp[i]=max(dp[i-1]+a[i],a[i]); dp[i]表示一这个点结尾的最大连续子序列 因为还要记录序列的头和尾,用start[]记录每个点在该序列的起始位置 注意提示要用scanf啊,cin会TLE /************************************************************************* > File Name: hdu1231.cpp > Author: yang > Mail:[email pr