• 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
    ",m,A[lefts],A[rights]);
    59         }
    60         else 
    61             printf("0 %lld %lld
    ",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
    ", ans, a[fir], a[la]);
    27     }
    28     return 0;
    29 }

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

  • 相关阅读:
    C++ CheckListBox
    TreeView查获节点并选中节点
    创建文件自动重命名
    bat
    Edit显示行号
    FindStringExact
    Extended ComboBox添加图标
    C++ Combobox输入时自动完成
    C++ ComboBox基础
    C++ Code_combobox
  • 原文地址:https://www.cnblogs.com/Wade-/p/6359165.html
Copyright © 2020-2023  润新知