zoukankan      html  css  js  c++  java
  • 【算法11】和为n的连续正数序列

    【题 目】输入一个整数,输出所有和为n的连续正数序列。例如:输入15,由于15=7+8=4+5+6=1+2+3+4+5,所以输出的序列为『1,2,3,4,5』;『4,5,6』,『7,8』三个。

    【思路1】从等差数列的观点考虑:如果有一列数满足i+(i+1)+...+j=n,根据等差数列的求和公式,我们容易得到:(i+j)(j-i+1)/2=n,即(i+j)(j-i+1)=2n,由于i,j均为正整数,我们容易得到(i+j),(j-i+1)也都为正整数,所以都是2n的因子,我们就可以从2到sqrt(2n)遍历2n的所有因子,对于其中的因子k,我们有:

      我们只需要保证j,i的值都为整数,并且i<j即可。根据这种思路我们有如下的代码:

     1 #include<iostream>
    2 #include<string>
    3 #include<cmath>
    4 using namespace std;
    5
    6 void FindContinuousSequence(int n)
    7 {
    8 int half = (int)(sqrt(2*n));
    9 for(int k = 2;k <= half;++k)
    10 {
    11 //找到因子k
    12 if((2*n) % k == 0)
    13 {
    14 int temp1 = 2 * n - k*k + k;
    15 int temp2 = 2 * n + k*k - k;
    16
    17 //开始数start,结束数end都为整数
    18 if(temp1 % (2*k) == 0 && temp2 % (2*k) == 0)
    19 {
    20 int start = temp1 / (2*k);
    21 int end = temp2 / (2*k);
    22
    23 //打印从start到end之间的所有数
    24 for(int i = start;i <= end;++i)
    25 cout<<i<<"\t";
    26
    27 cout<<endl;
    28 }
    29 }
    30 }
    31 }
    32
    33 int main()
    34 {
    35 cout<<"Enter your Number:"<<endl;
    36 int number = 0;
    37 cin >>number;
    38
    39 cout<<"the sum equals your number is:"<<endl;
    40 FindContinuousSequence(number);
    41 return 0;
    42 }

      运行结果如下:

      容易看出,这种算法需要遍历的范围是从2—sqrt(2n),因而时间复杂度为O(sqrt(n)),效率还算是比较高的,然而缺点是要计算很多的乘除,乘方运算,对于n值较大输入,计算过程会相对较慢。


    【思路2】我们从另一角度考虑这个问题,我们根据【算法10】中从两端想中间夹逼求解的基本思想,可以这样考虑:我们用一个small指示序列中最小值,用big指示序列中的最大值,因为和为n的序列至少需要两个数字,因而small取值从1到中点;如果small+big<n,就让big后移,以此增大sum;而如果small+big>n,就让small前移,以此缩小sum;如果small+big==n,打印从small到big之间的所有值即可。基于这种思路的代码为:

     1 #include<iostream>
    2 #include<string>
    3 using namespace std;
    4
    5 void FindContinuousNumbers(int n)
    6 {
    7 int small = 1;
    8 int big = 2;
    9 int middle = (n + 1)/2;
    10 int sum = small + big;
    11 while(small < middle)
    12 {
    13 if(sum == n)
    14 {
    15 for(int i = small;i <= big;++i)
    16 cout<<i<<"\t";
    17 cout<<endl;
    18 }
    19
    20 while(sum > n)
    21 {
    22 sum -=small;
    23 small++;
    24
    25 if(sum == n)
    26 {
    27 for(int i = small;i <= big;++i)
    28 cout<<i<<"\t";
    29
    30 cout<<endl;
    31 }
    32
    33 }
    34
    35 big++;
    36 sum += big;
    37 }
    38 }
    39
    40 int main()
    41 {
    42 cout<<"Enter your Number:"<<endl;
    43 int number = 0;
    44 cin>>number;
    45
    46 cout<<"The sum equals your number is as following:"<<endl;
    47 FindContinuousNumbers(number);
    48
    49 return 0;
    50 }

      运行结果如下图:

       效率分析:small指针要从1开始遍历到middle,而big指针则对于每一个small指针一直往前遍历,不存在指指针回溯的情况,因而整个算法的时间复杂度为O(N),效率较之前的算法的低,然而所有的操作都是简单的加减法,相比之前需要大量的乘法运算是一个优势。


    References:

    何海涛博客:http://zhedahht.blog.163.com/blog/static/25411174200732711051101/

    注:

    1)本博客所有的代码环境编译均为win7+VC6。所有代码均经过博主上机调试。

    2)博主python27对本博客文章享有版权,网络转载请注明出处http://www.cnblogs.com/python27/。对解题思路有任何建议,欢迎在评论中告知。

  • 相关阅读:
    Android studio USB连接失败
    BZOJ 1013 [JSOI2008]球形空间产生器sphere
    UVA1025
    noip2016天天爱跑步
    noip2015运输计划
    noip2012借教室
    BZOJ 1597: [Usaco2008 Mar]土地购买
    BZOJ1010: [HNOI2008]玩具装箱toy
    BZOJ1026: [SCOI2009]windy数
    BZOJ1801:[Ahoi2009]chess 中国象棋
  • 原文地址:https://www.cnblogs.com/python27/p/2275605.html
Copyright © 2011-2022 走看看