[problem12]欧拉
The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?
求解一个数的因子的个数,用暴力求解是最明显的做法,也是不可能算得出来的解法。这一题的作用也在于进一步揭示:算法的效率是要看场合的。在问题规模小的时候,再烂的算法都可以很快的执行并给出正确结果;但问题规模变大后,算法的优劣将体现的非常明显。
这一题,用暴力求解(用1-n的数字逐个被n除,统计被整除的次数,即因子的个数),根本算不出来。所以,这一题的关键就是:如何更快的求出一个数的因子的个数。解法:
a. 这里,关键是要认识并用到数学上关于因子分解的知识:一个数总是能唯一的表示为一组质数的乘积。任何因子都可以分解为质因子的乘积。一个数可以被任何一个质因子整除,必然可以被质因子的任意组合整除,即质因子的一个组合就是一个因子。可见因子的个数即质因子组合的个数。 (因子数的求解公式:将整数n分解为质因子相乘的形式,然后将每个质因子的幂分别加1之后连乘所得的结果就是n的因子的个数)详见代码注释。
View Code
#include <ctime>
#include <map>
using namespace std;
// get next triangle number in the sequence...
// count its factor number. if > 500, get the number printed.
//int getDivisorNumber(int val) // 暴力求解。。无终而果。。。。根本算不出来的。
//{
// int cnt = 2;
// for(int i = 2; i <= val/2; i++)
// {
// if(val % i == 0)
// cnt++;
// }
//
// return cnt;
//}
int getDivisorNumber(int val)
{
// 因为45= 3^2×5^1,45可以被3^0 ×5^0,3^0×5^1,3^1×5^0,3^1×5^1,3^2×5^0,和3^2×5^1,或者 1,5,3,9,15,和 45整除。
// 所以:算出所有质因子及对应的指数次方。所有指数次方的乘积就是所有因子的个数(所有组合的个数)
map<int, int> factorMap;
int i = 2;
while(val > 1)
{
if(val % i == 0)
{
map<int, int>::iterator itr = factorMap.find(i);
if(factorMap.end() == itr)
{
factorMap[i] = 2;
}
else
{
itr->second++;
}
val /= i;
i = 2;
}
else
i++;
}
map<int, int>::iterator itr = factorMap.begin();
map<int, int>::iterator itrEnd = factorMap.end();
int cnt = 1;
while(itr != itrEnd)
{
cnt *= itr->second;
itr++;
}
return cnt;
}
int _tmain(int argc, _TCHAR* argv[])
{
clock_t startTime = clock();
int index = 10; // start from the 10th number..
int formerSum = 0;
bool bIsReady = false;
while(true)
{
int sum = 0;
if(!bIsReady)
{
int i = 1;
while(i<=index)
{
sum += i;
i++;
}
formerSum = sum;
bIsReady = true;
}
else
{
sum = formerSum + index;
formerSum = sum;
}
// get its divisor number.
int cnt = 0;
cnt = getDivisorNumber(sum);
if(cnt > 500)
{
cout << sum << endl;
break;
}
index++;
}
clock_t endTime = clock();
double spentTime = difftime(endTime, startTime);
cout << "spentTime: " << spentTime << endl;
return 0;
}
b. 直接计算因子个数。不过只算到sqrt(n),然后把因子数*2作为总因子数。thread里很多人都是用这个方法。更快。。不过依据呢?没想出。
学到的:
0. 数学的知识对于思考算法,提升算法效率,非常有帮助。计算机可以帮你运算,但随着问题规模的变大,可能需要算很久。这时候,就必须人为的提升算法来提高速度了。
三角数: 第n个数是1至n的自然数的和。Sn = n(n+1)/2。两个三角形的和的1/2。 一般我们用Sn来表示1+2+3+…+n的值。现在要知道Sn的数目,我们可以设想有另外一个Sn(这里用白圆球来表示),把它倒放,并和原来的Sn靠拢拼合起来;我们就得到一个菱形(图二,这里n是等于4的情形),总共有n行,每一行有n+1个圆球,所以全部有n(n+1)个圆球。这是两个Sn,因此一个Sn应该是n(n+1)÷2。
参见百度百科: http://baike.baidu.com/view/467293.htm
级数(等差数列,等比数列)
--等差数列:公差是d。第n项公式是 An = A1 + (n-1)d; 前n项和公式是: A1 + A1 + d + A1 + 2d + ... + A1 + (n-1)d = nA1 + d* (n-1)n/2
--等比数列:公比是q。第n项公式是 An = A1* q^(n-1); 前n项和公式是: A1 + A1*q + A1*q^2 +.. + A1*q^(n-1) = ()(1-q)/(1-q) = A1*(1-q^n)/(1-q)
2. 判断质数和求解质因子,因子
判断质数:首先,除了2,其他都是奇数;limit是被判断数的平方根。
求解质因子:任何数都可以唯一的表示为一组质数的乘积。任何因子肯定可以分解为质因子的乘积。
求因子:一般情况下,一般求解法足够。特殊情况下,考虑到质因子和因子之间的关系。


浙公网安备 33010602011771号