算法与程序设计:第二篇 正整数拆分为连续正整数之和

问题:试把一个正整数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)

 

猜你喜欢

转载自blog.csdn.net/biubiuxin/article/details/81138460