该问题出自《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 | > |