1. 程式人生 > >將一個正整數n,拆分成連續的自然數之和,輸出所有可能的情況

將一個正整數n,拆分成連續的自然數之和,輸出所有可能的情況

http://blog.csdn.net/kennyrose/article/details/6544518  本文連結,感謝分享!!

from程式設計之美2.21

問題描述:將一個正整數,拆分成連續的自然數之和,輸出所有可能的情況

例如: 3 = 1+2

        10 = 1+2+3+4

        16 = 5+6+7

        ...

問題求解: 

連續的自然數之和讓我們想到了等差數列求和公式:

其中Sum為要分解的正整數,n為連續自然數的個數,aFirst為連續自然數的第一位數

將以上公式改寫成另外一種格式

求解得到連續自然數個數n:

如果一個數可以分解為幾個連續自然數之和,那麼就意味著方程有解,那麼對於相應的解就有如下限制,

必須為平方數且開根號的結果必須為奇數

需要注意一點的是:由於是連續自然數,所以首項aFirst必定不可能大於n/2,所以不需要從1-n遍歷,只需要從1- n/2 遍歷即可

c++程式碼如下所示

  1. // partitionSum.cpp : Defines the entry point for the console application.  
  2. //  
  3. #include "stdafx.h"  
  4. #include <math.h>  
  5. int main(int argc, char* argv[])  
  6. {  
  7.     // 等差數列求和公式 Sum = n*aFirst + n*(n-2)/2;
      
  8.     // Sum 為要拆分的整數,  
  9.     // n 為拆分後連續自然數個數  
  10.     // aFirst 為連續自然數中的第一位數  
  11.     int Sum, aFirst;  
  12.     int i,j;  
  13.     int w,k,m;    
  14.     printf("請輸入要分解的自然數Sum: ");  
  15.     scanf("%d",&Sum);    
  16.     printf("/n");    
  17.     for(i = 1; i <= Sum/2; i++)  //由於是連續自然數,所以首項必定不可能大於n/2  
  18.     {    
  19.         aFirst = i;                        
  20.         w = (2*aFirst-1) * (2*aFirst-1) + 8*Sum;    
  21.         k = (int)sqrt(w);    
  22.         m = k - 2*aFirst + 1;    
  23.         if(k*k != w)  // k是一個平方數  
  24.             continue;    
  25.         else if(m %2 !=0)  // m必須為偶數  
  26.             continue;    
  27.         else    
  28.         {    
  29.             printf("可以分解%d個連續自然數:/n",m/2);    
  30.             for(j=1;j<=m/2;j++)    
  31.                 printf("%d ",i+j-1);    
  32.             printf("/n/n");    
  33.         }    
  34.     }    
  35.     return 0;    
  36. }  

結果如下圖所示: