• 课后实验5--返回一个整数数组中最大子数组的和(首尾相接改良版)


    伙伴链接:http://www.cnblogs.com/chengqiqin07/

    一、设计思想

       本次实验是在前一次的实验的基础上将初始数组的头和尾部连接起来,形成环,在环中寻找子数组中和的最大值。

       关于寻找环状数组中子数组和的最大值,在课堂上按照老师的提示,将初始数组首尾相接形成环,再将其从任意一点断开,形成不同的数组,再从中找出子数组中和的最大值。于是我们进过思考,既然断裂的部位是随机的,那么初始数组中任意的一个数都可能成为断裂后数组的第一个数,且可以利用循环可以实现,循环次数就是初始数组中数的个数。将循环套在之前计算子数组和最大值的循环的外面就可以基本实现本题目的要求。

       关于返回最大子数组的问题,在每一次调整数组顺序后,根据max函数选择的子数组和变化,若当前数是和最大子数组中的一个元素,那么记录其初始位置,使其值为该循环次数的计数器的值,同理,判断出和最大子数组的结束位置,由于该数组是一个环,因此利用减去数组长度值来实现数组呈链状向后推移。最后输出初始位置和结束位置之间的子数组位置。

    二、出现的问题

       关于这次的实验,我们在一开始对题意的理解上出现了分歧,我们其中一个认为是将初始数组的首尾相接,在环中寻找其子数组和的最大值,思路就是和设计思想中利用循环嵌套来实现,而另一个认为是将所有子数组首尾相接,在计算子数组和的时候导致了互相听不懂对方的思路,后来经过询问同学以及讨论,最终确定了这次编程的大致方向。

       在寻找环状数组中子数组最大值的时候,最大值的判断环节能够顺利完成,比较费周折的是输出和最大值子数组的位置,这也就意味着需要记录初始位置以及结束位置这两个数值,在一般情况下,根据设计思路基本能够实现此功能,但是在特殊情况下,比如有两个子数组都是和最大的子数组,还有就是在所有数都是正数的时候,和所有数都是负数的时候,会出现问题,经过我们改正,使得都是正数和负数的情况下,子数组位置是正确输出的,而在出现多个和相等且最大的子数组时,只能输出其中的一个位置。

    三、可能的解决方案

      本次实验的大致框架和思路是保持一致的,在记录和最大子数组位置的环节,我们讨论了两种解决方案:

       1.在输入初始数组时,记录每一个数字的位置,在判断子数组和最大值的时候判断当前数是初始数组的哪一个数,输出其位置,但是初始数组中数值相同时会出现问题,因此没有选择这种方法。

       2.在每一次调整数组顺序后,根据max函数选择的子数组和变化,若当前数是和最大子数组中的一个元素,那么记录其初始位置,使其值为该循环次数的计数器的值,同理,判断出和最大子数组的结束位置。

    四、源程序

    //2016 3.21 Cheng Qiqin  Hao Ying
    //返回一个整数数组中最大子数组的和
    
    #include<iostream>
    using namespace std;
    
    int main()
    {
        int Array[100],sumOfArray[100],location[100][2],loc=0;//sumOfArray用于存放包含目前数的子数组的和的最大值,sum用来存放不包含当前数的所有子数组的和的最大值
        int i,j,length=0,sum,n=0, NegExit=0,Max;//用来记录数组长,sum用来存放不包含当前数的所有子数组的和的最大值,NegExit用来记录数组是否不含有正数
        cout<<"请输入数组:"<<endl;
        for(length=0;;)
        {
            
            cin>>Array[length];
            if(Array[length]>0)//出现正数
            {
                NegExit=1;
            }
            length++;
            if(getchar()=='
    ')
            {
                break;
            }
        }
        cout<<"这个数组的长度为:"<<length<<endl;
        if(NegExit==1)//数组中有正数时,需要找到和最大的子数组,并记录子数组的位置
        {
            for(i=0;i<length;i++)
            {
                sumOfArray[i]=Array[0];
                sum=0;
                location[i][0]=i;
                location[i][1]=i;
                for(j=1;j<length;j++)
                {
                    sum=max(sum,sumOfArray[i]);
                    if(sumOfArray[i]<0&&sum<Array[j])
                    {
                        location[i][0]=i+j;
                        location[i][1]=i+j;
                    }
                    sumOfArray[i]=max(sumOfArray[i]+Array[j],Array[j]); 
                    if(sum<sumOfArray[i])
                    {
                        location[i][1]=i+j;
                    }
                }
                int arr=Array[0];//将数组中的数向前移,实现数组首尾相连的功能
                for(j=1;j<length;j++)
                {
                    Array[j-1]=Array[j];
                }
                Array[length-1]=arr;
                sumOfArray[i]=max(sum,sumOfArray[i]);//到数组中第i个数依次移到第一位时和最大的子数组的和
                if(i>0)
                {
                    if(sumOfArray[i]>sumOfArray[i-1])
                    {
                        loc=i;            
                    }
                    sumOfArray[i]=max(sumOfArray[i-1],sumOfArray[i]);//此时所有子数组的和最大的值
                }
            }
            Max=sumOfArray[i-1];//这个整数数组的子数组之和的最大值
        }
        else//当数组中不存在正数时
        {
            Max=Array[0];
            for(i=0;i<length;i++)
            {
                if(Max<=Array[i])
                {
                    Max=Array[i];
                    location[loc][0]=i;
                    location[loc][1]=i;
                }
            }
        }
        cout<<"这个整数数组的子数组之和的最大值为"<<Max<<endl;
        cout<<"子数组之和最大子数组的位置为:"<<endl;
        cout<<"注:输出的数表示这个子数组的每个元素是整数数组的第几个数"<<endl;
        cout<<"    若数组中有多个子数组之和最大,输出其中的一个"<<endl;
        cout<<"和最大的子数组位置为:";
        for(j=location[loc][0];j<=location[loc][1];j++)
        {
            if(j<length)
            {
                cout<<"Array["<<j<<"] ";
            }
            else
            {
                cout<<"Array["<<j-length<<"] ";
            }    
        }
        cout<<endl;    
        return 0;
    }

    五、结果截图

    当数值中既有正数又有负数:

    当数组中都是正数:

    当数组中都是负数:

    六、总结

       通过这次的实验,使我在之前实验:返回一个整数数组中最大子数组的和的基础上学到了更多的知识,更加的锻炼了我的逻辑思维,使我对于计算子数组和的最大值的方法得到了更加深入的了解。在之前实验的基础上使我们能够沿着之前的思路继续进行其他的功能实现。

       本次程序在之前程序的基础上又有了新的难度,要将数组首尾相接,再判断其子数组和的最大值,一开始的时候还是一头雾水,经老师课堂上的提点,课下我们反复斟酌了老师的意思,最后完成了此功能。再此过程中,我觉得我有很多收获,首先在两人的讨论下,会发现许多自己想不到的问题,这就使我们的编程效率提高了,减少了走弯路的时间。在调试程序时,出现问题时,通过两人讨论,相互帮助,可以尽快解决问题,这也使我们之间更有默契,合作更加协调。比如在寻找子数组位置的时候,在限制条件中由于之前的测试事例都是既有正数也有负数的,因此在if语句中有大于零和小于零的限制,忽略了都是正数和都是负数的情况,在彼此的帮助和复审,调试的过程中将错误的地方找了出来。

       我觉得这次的实验核心就是找到子数组的位置,这是考验我们能力的一个点,虽然我们知道在考虑的方面肯定还存在着不足,我们考虑的还不是很周全,但是我们在这个过程中还是收获了许多的经验,在接下来的实验中,我会更加努力,锻炼我的思维能力以及编程能力的!

    七、工作照

  • 相关阅读:
    kmp模板
    2017 ACM/ICPC Asia Regional Shenyang Online transaction transaction transaction
    2017 ACM/ICPC Asia Regional Shenyang Online 12 card card card
    KMP
    最长不下降子序列
    codeforces round 433 D. Jury Meeting
    codeforces round 433 C. Planning 贪心
    hdu 5792 线段树+离散化+思维
    hdu 5792 树状数组+离散化+思维
    hdu 5791 思维dp
  • 原文地址:https://www.cnblogs.com/haoying1994/p/5317169.html
Copyright © 2020-2023  润新知