码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 1231 最大连续子序列

时间:2017-01-31 22:32:29      阅读:293      评论:0      收藏:0      [点我收藏+]

标签:起点   hdu   logs   开始   执行顺序   ace   为什么   运行时   can   

这道题是学校寒假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 }

 

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

hdu 1231 最大连续子序列

标签:起点   hdu   logs   开始   执行顺序   ace   为什么   运行时   can   

原文地址:http://www.cnblogs.com/Wade-/p/6359165.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!