将一个正整数,拆分成连续的自然数之和,输出所有可能的情况
例如: 3 = 1+2
10 = 1+2+3+4
18 = 5+6+7
偶然见到这个问题,这里写下自己的解法。
分析:
对给定整数x以及一组满足要求的数字序列:a1a2……an,有
x=a1+a2+……an
数字的序列可以看做是一个公差为1的等差数列,数列的和根据数列的性质,可以得出满足要求的序列的一些性质。
数列的和即x可以数列的一项或两项来表示:
n为偶数时,x=(ai+aj)*n/2;i+j=n+1 (1)
n为奇数时,x=n*ak;k=n/2+1 (2)
1.从中可知,若n为奇数,则x一定可以被n整除,而这n个数字中间的一个就是x/n,并且可以据此得出这个数左右各(n-1)/2个数字。
若n为偶数,则(1)中的i和j可以取特定的两个值n/2、n/+1;ai和aj是相邻的两个数字,则有ai+aj是奇数,x/n=(ai+aj)/2,则有x不能被n整除,而2x可以被n整除。对于任一对i+j=n+1都有ai+aj,取i=1,j=n,可以解出a1,再依次加一得到序列的其他数字。
2.对于长度一定为n的连续自然数串,和最小的序列应该是1,2……n,和为n(n+1)/2,如果x
即应该满足:n(n+1)/2<=x →n^2<2x
由以上内容可以写出伪代码如下:
decompose(x):
n=1
while(n*n<2x)
do
if(n%2==1&&x%n==0) 有该长度数字序列
if(n%2==0&&2x%n==0&&x%n!=0) 有该长度数字序列
n++
done
c代码:
void decompose(int num)
{
//序列的长度
int i=1;
int k=0;
//序列第一个数字
int aFirst;
printf(“%d:\n”,num);
while(i*i<2*num)
{
if(i%2==1)
{
if(num%i==0)
{
aFirst=num/i-i/2;
for(k=0;k
printf(“%d “,(k+aFirst));
}
printf(“\n”);
}
}
else
{
if((2*num)%i==0&&num%i!=0)
{
aFirst=num/i-(i/2)+1;
for(k = 0;k
{
printf(“%d “,k+aFirst);
}
printf(“\n”);
}
}
i++;
}
}