问题:试把一个正整数n拆分为若干个(不少于2个)连续正整数之和。
例如,n=15,可拆分为:
15=1+2+3+4+5,
5=4+5+6,
15=7+8。
这三种情况。
算法分析
1、应用求和公式优化设计(穷举法)
算法点津:
(1)观察上述规律不难看出,拆分后的数字满足以下三个条件:
a、每组数总会有一个起始项i,i可以是1,也可以是其它数;
b、每组数总会有一个或一个以上的累加项,记为i+k;k为1,2,3...;
c、(重要)每组数必满足公式: sum = i + (i+1) + ... + (i+k) = (k+1) * (2*i + k) / 2。
(2)先进行第一次循环for(int i=1;i<num/2;i++),由于题目给出拆分为不少于两个数,且为连续数,故为i<num/2;
(3) 在进行第二次循环for(int k=1;;k++),k为累加项,故从1开始,可以一直加到满足上面的公式,所以也不需要循环限制条件。
(4)(重要)判断:
注:num为输入的整数。
1、若sum>num,则跳出两次循环,回到第一次循环,执行下一步;
2、若sum==num,即i和i+k为所求整数,继续下一步,打印结果。
代码块1:
#include<iostream>
using namespace std;
int main()
{
int i,k,num, sum = 0;
cout << "请输入整数:";
cin >> num;
for (i = 1; i <= num / 2; i++)
{
for (k = 1;; k++)
{
sum = (k + 1)*(2 * i + k) / 2;
if (sum > num)
break;
if (num == sum)
{
for (int j = i; j < i + k; j++)
{
cout << j << "+";
}
cout << i + k <<"="<<num<< endl;
}
}
}
system("pause");
return 0;
}
复杂度分析
时间复杂度为:O(n^2)
2、公式逆用法
算法点津:
由1知公式sum=k*(2*i+K-1)/2也是成立的,我们可以把sum看成已知量num,得出起始项i= ( 2*num/ k - k + 1) / 2,然后遍历k即可。这样,就可以将时间复杂度降低了。显然,需要先想到1的方法,进而得到此方法,难度略为加大。
代码块2:
#include<iostream>
using namespace std;
int main()
{
int num, i;
cout << "请输入整数:";
cin >> num;
for (int k = 1; k <= num / 2; k++)
{
if (2 * num % k == 0) //由公式k * (2 * i + k - 1) = 2 * num知道2 * num能够被k整除
{
i= (2 * num / k - k + 1)/2;
if (i>0 && i!= 0) //能被2整除且保证第一位不为0
{
if (k > 1)
{
for (int j = i; j < i + k - 1; j++)
cout << j << "+";
cout << i + k - 1 << "=" << num << endl;
}
}
}
}
system("pause");
return 0;
}
复杂度分析
时间复杂度为:O(n)