对于函数gcd(欧几里得)的递归定理:
gcd(a,b)=gcd(b,a mod b)
对于这个函数的证明,真的是费劲了口舌,推出一大堆看的似懂非懂的公式,最后我只得出了一个结论:根本不需要公式证明。
设gcd(a,b)=k,则a=xk,b=yk。而当a mod b之后答案也一定是zk。这个z是x mod y的结果,但是最后一定是跟着一个因数k的,所以我们知道a mod b与a b之间的关系一定是线性的,成为所谓的线性组合,所以gcd(a,b)一定等于gcd(b,a mod b).
举个例子:
例如a=50,b=20,则k=10,x=5,y=2,z=1,则最后的答案=zk=1*10=10.虽然当a mod b=0的时候我们知道zk的答案不对,但是b=0其实a就是最大公因数了,无需再分解。
根据如上的证明我们可以举一反三,推出很多其它的例子,例如:
当求a*i mod b的值的时候,其实我们以推断出就等于gcd(a,b)的值。为什么呢?
举个栗子:
a=6 b=4 ans=2
12 4 0
18 4 6
24 4 0
30 4 2
36 4 0
...
我们从中可以看出,当gcd(a,b)的值大于1的时候,每次增加一个a,其实不过是增加其gcd(a,b)*k罢了,k=a div gcd(a,b)。
所以我们可以得出如下结论:
如果一个数与另一个数存在一个最大公因数,即第一个数或第二个数不管加多少个自己,都是加了多少个最大公因数,所以其实他们最后的结果不变。
再举一个例子:
我们可以根据欧几里得算法推广出一个新的思想——给出任意两个正整数a,b。需求出最大公因数d和满足下式的整系数x,y。
d=gcd(a,b)=ax+by(x,y是有可能为负数)
算法如下:
1、先用递归方式求出当b=0的时候最大公因数a,以及x和y的初始值,x=1,y=0.然后我们因为a,b在弹栈的过程中一直变化,所以x,y的值也需要一直变化。我们知道,当前得到的x,y值其实是对应b,a mod b这两个值的,而不是对应a,b,因为在弹栈的第一步,a,b就变化了,而现在我们的x,y值还没变化。
2、所以我们需要根据x,y和b,a mod b来求出当前的x,y值。
3、最大公因数d=gcd(a,b)=gcd(b,a mod b)。
为了得到新的x,y我们可以利用如下等式进行化简:
d=bx+(a mod b)y
=bx+(a-⌊a/b⌋b)y
=bx+ay-⌊a/b⌋by
=ay-b(x-⌊a/b⌋y)
所以我们可以用
t=x x=y y=t-(a div b)*y
这个交换算式来满足等式d=ax+by,显然次算法是正确的。
借用一张图来看一下过程:
由此我们可以看出99,78的最大公因数是3,是由14*78+99*-11得来的。
根据如上算法我们又可以将经典的搜索bfs倒水问题转换成不定方程解答。