1、用辗转相除法求最大公约数和最小公倍数
求两个数a,b的最大公约数,可以用什么方法?尽管依次试除也能得出相应的结果,但是时间效率太低。而且还有一个简单、高效、相当优美的算法——辗转相除法。也许这是最广为人知的数论算法了。
这个算法的关键在于以下恒等式:gcd(a,b)=gec(b,a mod b)。它和边界条件gcd(a,0)=a 一起构成了以下的程序:
int gcd(int a, int b){return b == 0 ? a: gcd(b, a%b)};
这个算法成为欧几里得算法。既然是递归,我们免不了就要问一句:会导致栈溢出吗?答案是:不会。可以证明,gcd函数的递归层数不会超过4.785lgN + 1.6723 ,其中N=max{a,b}。值得一提的是,让gcd递归层数最多的是gcd(Fn,Fn-1),其中Fn就是鼎鼎大名的斐波那契数。
另外,利用gcd,还可以求出两个整数a和b的最小公倍数lcm(a,b),只要用这两个数的乘积除以最大公约数即可。即 gcd(a,b)*lcm(a,b)=a*b 。
int lcm(int a, int b){ return a/gcd(a,b) * b};
注意公式的写法:如果把lcm写成 a*b/gcd(a,b),可能会得到错误的答案——a*b可能会溢出!使用上述写法,只要保证最终结果在int范围之内,这个函数就不会出错。
2、筛选素数表
3、求某个区域内的点:
例:果园里的树排列成矩阵,他们的x和y坐标均是1-99的整数。输入三角形的三点坐标,一次统计每一个三角形内部(包括边界)共有多少课树。如图所示:
样例输入:
1.5 1.5 1.5 6.8 6.8 1.5
10.7 6.9 8.5 1.5 14.5 1.5
样例输出:
15
17
最容易想到的方法是逐一判断。对于每个点(x,y),看看它是否在三角形内。但是这种算法有缺陷:当三角形很大时,时间复杂度为O(mn)。肯定会超时。
下面先来看这个函数:
double area2(double x0, double y0, double x1, double y1, double x2, double y2)
{return fabs(x0*y1+x2*y0+x1*y2-x2*y1-x0*y2-x1*y0)};
很明显能看出来这是什么吧,如果两条三角形的边是AB,AC,那么这个函数就是计算两条边的外积,而结果刚好是三角形面积的两倍!
计算方法如下:
注意:由于向量不同的方向会导致计算结果分正负,用fabs统一即可。
有了它,判断就很简单了。假设输入三角形为ABC,待判断的点为O,则O在三角形内部或边界上满足的条件为:ABC的面积\OAB的面积+OAC的面积+OBC的面积。
另外为了避免浮点误差,尽量使用fabs(a-b)是否小于一个事先给定的值(如1e-8),如果可能,尽量避免浮点运算。
4、抽屉原理
把不少于n+1个的物体放到n个抽屉里,则至少有一个抽屉里的东西不少于两件。
看起来像是废话,但是运用到实际做题中能发挥很强大的功能,如下:
例:从自然数中取出任意n个正整数,组成序列a1,a2,...an。证明:存在一段连续的序列和,让和为自然数n的倍数。
我们可以先构造一个序列si=a1+a2+...ai,然后分别对于si取模,如果其中有一个sk%n==0,那么a1+a2+...+ak就一定是n的倍数(该种情况得证)
如果任何一个sk%n != 0 ,那么 si%n 的范围必定在[1,(n-1)]之间。所以原序列就产生了n个余数。
余数有n个,范围有n-1个,所以必定有两个余数会重复,所以sk1与sk2的差是n的倍数。
因为sk1-sk2是一段连续的序列,所以原命题得证。
5、杨辉三角与二项式定理
二项式计算:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
杨辉三角里一个很重要的特点点是:每个数字等于上一行的左右两个数字之和。
可用此性质写出整个杨辉三角。即第n+1行的第i个数等于第n行的第i-1个数和第i个数之和,这也是组合数的性质之一。即
很明显,二项式定理的系数与杨辉三角一致,因此,很容易短时间内求出(a+b)^n中所有项的系数。
注意:写组合公式函数时,避免多项数据的连乘导致的数据溢出。可以用边乘边除的方法。这样,只要所求的最终结果在范围之内,就不会出错。
6、斐波那契数列
先考虑一个简单的问题:楼梯有n个台阶,上楼可以一步上1阶,也可以一步上2阶,一共有多少种上楼的方法?
可以先这样考虑:假设f(n)为n个台阶的走法总数,把n个台阶的走法分成两类:
1):第一步走1阶,剩下还有n-1阶要走,有f(n-1)种方法。
2):第一步走2阶,剩下还有n-2阶要走,有f(n-2)种方法。
这样,就得到了递推式:f(n)=f(n-1)+f(n-2)。不要忘了边界情况f(1)=1,f(2)=2。
常用的:
奇数项求和:
偶数项求和:
将杨辉三角左对齐,成如图所示排列,将同一斜行的数加起来,即得一数列1、1、2、3、5、8、……
很神奇吧!斐波那契数列和杨辉三角居然是相通的!