问题描述:
输入一个正整数N,输出能相加等于N的联系序列的和(序列必须多于1项),如果这种序列存在,则输出所有这样的序列,如果不存在,则输出NULL。
例如:输入为15
输出:
1+2+3+4+5=15
4+5+6=15
7+8=15
首先我们先分析一下这个问题:
1. 首先1和2是不能表示成连续的自然数之和的,所以我们从3开始
2. 假设n可以表示成连续的自然数之和【s,t】,那么根据求和公式则有(s+t)*(t-s+1)=2*n
3. 把2*n表示成两个自然数相乘,则2*n = a * b
4. 另 s+t=a , t-s+1=b,解方程可得s=(a-b+1)/2, t=(a+b-1)/2
5. 要使得s和t为自然数,那么必须满足a-b和a+b都是奇数
6. 我们在来讨论一下n的奇偶性,如果n是奇数那肯定可以表示为n=2*i+1,至少可以分解为【i,i+1】,所以肯定有解
7. 如果n是偶数,则n可以分解为n=2^i*3^j*….,假定只有i不为0,后面的j,k…幂次都为0,那么所有的因子都为偶数,不可能满足两个因子为奇数的条件。
8. 所以我们可以发现,只要n不是2的幂次并且大于等于3,就一定可以分解为连续正整数之和。
方法1:
使用简单的循环来进行枚举判断,从一个数为1开始枚举,当和大于n时,把第一个数加1,以此类推,此处采用上面推导的n必须为2的幂次直接判断。
参考代码:
#include <stdio.h>
int IsCanFind(int n)
{
if (n < 3)
return 0;
return n & (n - 1);//如果n是2的幂次则不能找到
}
int main()
{
int n, i, j, k, nSum;
printf("input a number: ");
scanf_s("%d", &n);
if (0 == IsCanFind(n))
{
printf("NULL\n");
return 0;
}
for (i = 1; i < (n + 1) / 2; i++)//只需要找到n的一半就可以了,因为再往下找肯定大于n了
{
nSum = 0;
for (j = i; j <= n; j++)
{
nSum += j;
if (nSum == n)
{
if (i == j)
break;//这里只有一个元素可以直接退出该层循环,因为后面再加肯定不满足了
printf("%d&