这两天学了《算法笔记》中的数学问题相关部分,加减乘除、分数、素数部分还好,一个小学学过,一个之前接触过比较多次,后面又学了大整数的加减乘除,感觉也还好,就是用字符串输入,然后存到数组里,逐位进位运算。再后来...later
先说学了欧几里得算法,用来求最大公约数和最小公倍数。最大公约数嘛,证明我已经不太记得了,只记得gcd(a,b) = gcd(b,a%b)当前面那个参数为0时就返回1了。不对,这说得好乱啊,还是细细回忆一下先。
首先,如何求最大公因数呢?6和4的最大公因数显然是2,4可以分解为质因子乘积2*2,6可以分解为质因子乘积2*3,然后取公共部分乘积2,得到6和4的最大公因数为2,这是我们自己手动计算最大公因数常采用的方法。而欧几里得辗转相除法又是怎么推导的呢?假设a,b的最大公因数为gcd,那么必然有 a%gcd = 0 和 b%gcd = 0 ,这是显然的,因为gcd既是a的因数,又是b的因数,那么gcd必然整除a,也整除b,显然上面两个式子还不足以描述gcd是a,b的“最大”公因数,充其量描述出gcd是a和b的公因数,那么怎么描述gcd是a和b的最大公因数呢?思考一下,可以发现,好吧,没发现什么... 尝试search一下,a和b之间有什么关系呢,由于a,b都是整数,那么a一定可以表示为kb + r, 其中k为a/b商,r为a%b模。即有a = kb + r。 试着移一下项,r = a - kb。好像还是看不出什么... 接着research一下,来看看r这个式子,发现r可以表示为a和b的线性关系,这是一个惊人的发现...也就是说r%gcd = 0。也就是说,如果gcd是a和b的最大公因式,那么gcd也一定是b和r的公因数,而且一定是最大公因数,b和r的最大公因数不可能a和b的最大公因数还大(当然这里讨论的是两个正整数的最大公因数),所以若a和b的最大公因数gcd是b和r的公因数,那肯定是b和r的最大公因数,即有gcd(a,b) = gcd(b,r),如果r=0意味着什么呢,那就意味着a%b=0,那么显然b就是a和b的最大公因数了,也就是gcd函数的第二关参数为0时第一个参数为所求的最大公因数。
看书上欧几里得的严谨证明也是看了又忘,总结一下记一记结论吧(反正我是记不住证明了),总之,两句话,两个整数a,b,如果a除以b余数为0的话,那么b就是gcd,否则转换为计算gcd(b, r),其中r= a%b。代码挺好记:
int gcd(int a,int b){
if(b == 0){
return a;
}
return gcd(b, a%b);
}
然后最小公倍数怎么求呢?利用上面求出的最小公约数gcd,最小公倍数lcm就是a*b/gcd,当然最好在代码中写成a/gcd*b以防乘法溢出,书中的解释非常明了,只需要在脑海中构想一张集合的维恩图就行:(想象集合中的元素为乘积分解的质因子,当然这里质因子可以重复,举个例子,12和8,可以将12想象为集合{2,2,3},8可以想象为集合{2,2,3},则最大公约数集合为交集{2,2},最小公倍数集合为并集{2,2,2,3}。
咋搞呢?写到这里,再总结一下,学了些啥:
1.gcd和lcm:掌握程度:记得求法,能写代码,可以算过
2.分数的表示(结构体)、化简、加减乘除:掌握程度,明白原理,理解代码(,还没去写,,,
3.素数求法:暴力法没啥好说的就是根据定义一个个试,主要掌握两种新的方式,一是埃式筛法,原理就是如果从小到大遍历到某个数时,它还没有被前面的数筛掉,那么它一定是素数。因为如果不是素数,它一定是某个小于它的数的倍数,就一定会被前面的数筛掉,这算是反证法吧。二是避免重复计算,以空间换时间,将计算出来的结果存到数组中,可以弄个素数表。掌握程度:掌握原理,理解代码(但还没练习...
4.质因子分解:忘了差不多了,大概是用素数表,从小到大开始算,用待分解数n,除以这个素数,除到不能除为止,然后除下一个,直到素数大于n就停止,每次记录指数...好像不太难,就是前面会求素数之后的小扩展应用。掌握程度:有求解思路,但还没练习...
5.大整数加减乘除:输入用字符串存储,再转存到整型数组中,逐位加减乘除时用小学学过的加减乘除知识即可,这里要用到一个变量存储每次一位运算的进位,注意乘法一位运算的进位可能不止一位,用好整数除法和模运算就能轻松化解。另外要注意高位0要去掉同时又要保证至少有一个数。别的没啥了,掌握程度:掌握方法思路,但还没练习...
6.扩展欧几里得算法:看得迷糊,想摆烂怎么办?哈哈哈,算了,慢慢来吧,先记一下结论,后面再回顾也许就思路清晰了呢,证明啥的就先放在这里当个遗留问题吧,阿巴阿巴...
7.组合数求解:这里好像要用到前面扩展欧几里得算法的相关知识,但是据我的记忆,组合数求解就是涉及求阶乘嘛,主要方法有三种,一是暴力求解(一种定义式暴力求解,一种定义式的变形暴力求解,反正都挺暴力的(bushi)...好好好,暴力占了两种,剩下一种方式是推导递推公式,写代码就使用递归手段或者递推方法(注意递推时可以存储前面计算的结果,以空间换时间)求解。然后注意一个规则和一个规律。规则就是C上0下n = C上n下n = 1; 规律就是 C上m下n = C 上n-m下n.好吧,漏了一个东西没说,新学的,就是如果求组合数然后对一个素数p取模的话,可以用Lucas(卢卡斯)定理,个人觉得还算好记吧,话是这么说的,至于明天忘记还是后天忘记就不好说了,,,不过需要质因子分解,写成p进制。掌握程度:勉强会求,但不是很会...听君一席话,如听一席话...也还没练习...
扩展欧几里得算法(Extend Euclidean Algorithm)
几个结论记一记;
1.扩展欧几里得算法解决了什么问题?求ax + by = gcd(a,b)的解。对于gcd(a,b)对应的x1,y1。 对于gcd(b,r)对应的x2,y2。 有递推公式x1 = y2, y1 = x2 - ky2。(其中k=a/b商)。利用exGcd可以求出一组解,而全部解就等于这一组解推过来,x,y的所有解分别以b/gcd和a/gcd为周期。有x'=x+Kb/gcd;y'=y-Ka/gcd。(K为任意整数)
2.方程ax+by=c的求解,设上面扩展欧几里得算法求出的一组解为x0,y0。则该方程有解的充要条件为gcd整除c。一组解为x=cx0/gcd;y=cy0/gcd;同理,全部解为x'=x+b/gcd;y'=y-a/gcd;(K为任意整数)
3.同余式的求解:a与b模m同余,则同余式为a三杠b(modm)。知道一个规律即可,a与b模m同余等价于a-b模m等于0.其他记不住了...然后这里学的是同余式ax三杠b(mod m)的求解,求逆元就是求ax三杠1(mod m)的解。但记不住具体解法,这里又要用到前面的方程求解公式...先放着吧
4.逆元的求解:这里学的是:b和c互为模m的逆元,即ab三杠1(mod m). b和c互为模m的逆元,则b模m的逆元为c,同理,c模m的逆元为b.
5.(b/a)%m:如下图:
总而言之,数学问题这里素数部分应该是一个重点,然后扩展欧几里得算法之类的是个难点。扩展欧几里得算法学得迷糊,,,后面我再慢慢思考总结一下扩展欧几里得算法的相关问题吧,主要是空谈公式理论确实记不住,先知道有这么个东西,后面刷到相关题目再慢慢熟悉融会贯通吧...(现在还是麻木的)