1. 程式人生 > >2.16 連續整數的固定和 C實現

2.16 連續整數的固定和 C實現

該問題出自《C語言名題精選百則技巧篇》

題目:編寫一個程式,讀入一個正整數,把所有那些連續的和為給定正整數的正整數找出來,例如,如果輸入27,發現2~7,8~10,13~14的和是27,這就是解答。如果輸入的是10000,應該有18~142,297~328,388~412,1998~2002這4組,注意不見得一定有答案,比如,4、16就無解,另外排除只有一個數的情況,否則每一個輸入就都至少有一個答案,就是它自己。

    不費腦筋的演算法就是,設定兩個變數i個j,令j>i,i從1到n/2,j從i+1到n/2+1,因為從i到j必須是連續的,並且i+j<=n,只有在j=i+1的情況下會有可能會發生i+j=n,如果i>n/2,j>i>n/2,因此i+j>n。因此i<=n/2;如果j>n/2+1,如果i = j-1>n/2, i+j>n。因此j<n/2+1。設定兩個for迴圈,將i到j的數相加,判斷和是否等於給定的數GIVEN。這樣做的問題當然可以找到i和j,但是當GIVEN數值特別大的時候,這種方法非常的浪費時間。

這種方法的程式碼為:

for(i=1;i<=n/2;i++)
    for(sum=i,j=i+1;j<=n/2+1;j++){
          sum+=j;
          if(sum == n)
                printf("\n%ld  ~  %ld",i,j);
      }

我們可以考慮以下幾點:

(1)用i+(i+1)+...+(j-1)+j來表示,那麼i<=n/2。上面已經證明過。

(2)如果某個和i+(i+1)+...+(j-1)+j比給定值GIVEN大,那麼要把和變小,但是仍然要維持遺傳連續的整數,拿掉j變成i+(i+1)+...+(j-1),不如拿掉i變成 (i+1)+...+(j-1)+j,拿掉j下降太快,不如拿掉i,再慢慢降低;

(3)如果 i+(i+1)+...+(j-1)+j比給定值GIVEN小,加上j+1變成i+(i+1)+...+(j-1)+j+(j+1)。

本文所採用的解法如下:

(1) 先求出一個和,sum=1+2+...+j; 並且sum是第一個大於等於給定值GIVEN的和,例如,GIVEN=27,那麼sum就是1+2+...+7 = 28. j=7作為j的初值

(2) 若和sum = i+(i+1)+...+(j-1)+j比給定值GIVEN大,就把和去掉最小的那一端,變成sum = sum -i = (i+1)+...+(j-1)+j;如果和sum = i+(i+1)+...+(j-1)+j 比給定值GIVEN小,就讓sum = sum +(j+1) 變成i+(i+1)+...+(j-1)+j +(j+1); 如果等於GIVEN,就把i和j顯示出來。

(3)以上步驟反覆執行,直到i>n/2為止。

程式如下:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    long left,right;
    long sum;
    long GIVEN;
    int count =0;
    printf("\nConsecutive sum to a fix given number");
    printf("\n=====================================");
    printf("\nPlease input a Given number--->");
    scanf("%ld",&GIVEN);
    for(sum = 0,right=1;sum<GIVEN;sum+=right,right++);
    
    for(left=1,right--;left<=GIVEN/2;){
        if(sum > GIVEN){
            sum -= left;
            left++;
        }else{
            if(sum == GIVEN){
                printf("\n%ld = sum from %ld to %ld",GIVEN,left,right);
                count ++;                         
            }  
            sum += (++right);    
        }                                   
    }
    if(count>0)
        printf("\n\nThrer are %d solutions in total.",count);
    else
        printf("\n\nSorry,threr is no solution at all.");
    while(1)
       getchar();
    return 0;
}
執行結果:


執行過程:

i~j 比較結果
1~7 28 >
2~7 27 =
2~8 35 >
3~8 33 >
4~8 30 >
5~8 26 <
5~9 35 >
6~9 30 >
7~9 24 <
7~10 34 >
8~10 27 =
8~11 38 >
9~11 30 >
10~11 21 <
10~12 33 >
11~12 23 <
11~13 36 >
12~13 25 <
12~14 39 >
13~14 27 =
13~15 42 >
可以看出該方法本文章開頭的演算法節省了很多加法計算。