~》》_《《~
咳咳!!!今天写此笔记,以防他日老年痴呆后不会解方程了!!!
Begin !
~1~, 首先呢,就看到了一个 gcd(a,b),这是什么鬼玩意呢?什么鬼玩意并不重要,重要的她代表的含义,其实呢,gcd(a,b)就表示 非负整数 a 和 b(不同时为0) 的最大公约数,(数论概论上说:计算 a 与 b 的最大公因数的更低效方法是我女儿四年级老师教的方法,老师要求学生求出 a 与 b 的所有因数,然后找出同时出现在两个表中的最大数字。 YES!A good idea for 小学生!) 。如今呢,我们自然不能这样算啦!
好吧!从求 gcd (a,b) 开始!
一般的有下列式子:
a = b * q1 + R1 ;
b = R1 *q2 + R2 ;
R1 = R2 * q3 + R3 ;
R2 = R3 * q4 + R4 ;
。。。。。。
。。。。。。
这样写下去什么时候才是个头啊~_~。。。
很显然 必然会有结束的地方的,因为肯定会有一个 R 为 0 (R2 >= R4 >= R6 ....,R1 >= R3 >= R5 ...),好吧,继续往下写:
Rn-1 = Rn * qn+1 + Rn+1 ;
Rn = Rn+1 * qn+2 + Rn+2 ;假设 Rn+2 == 0
。。。。。。。。。。。。。 ok!^_^ 。。。。。。。。。。。。。。
Rn+2 = 0了,那么由最后一个式子得 Rn+1整除Rn,接着,Rn+1 整除 Rn-1,,,,很显然的,这个递推可以推到第一个式子,so,Rn+1 整除 a,Rn+1 整除 b, 也就是说 Rn+1 是 a 与 b 的公约数了,是不是最大的呢?先把 Rn+1 记为 g,设 d 为 a 与 b 的任意一个公约数,由第一个
式子(a = b * q1 + R1)可以知道,d 整除 R1 ,再代入到第二个式子里得, d 整除 R2,推啊推,推啊推,最后知道了 d 整除 Rn+1,即 d 整除 g,
因为 d 是任意的公约数 , d 整除 g ,那么 取 d 为 最大公约数,则 g 既是公约数,又是最大公约数的倍数,只能是 :g 就是最大公约数。
在前面“,,,,递推 。。”里隐藏了一个惊天大秘密,那就是 gcd(a,b) = gcd(b,a%b),这个秘密啊,十分的奇妙!为啥有这个结论呢?从第一个式子(a = b * q1 + R1) 显然, gcd (a,b) = g; 再显然 gcd(b,r1) = g ; 。。。。。 显然嘛,gcd (a,b) = gcd(b,a%b),
。。。。。。。。。。。ok。这个问题算是解决了。代码附上。。。。。。。。。。。。。。。。。。。
1 int gcd(int a,int b) 2 { 3 return b==0?a:gcd(b,a%b) ; 4 }
~2~,好吧,其实前面只是闲扯!不过我可以赌五毛钱前面的东西没有偏题!
下面来正面解决这个问题:a*x + b*y = gcd(a,b) ;
一般的有下列式子:
a = b * q1 + R1 ; R1 = a - q1 * b ;
b = R1 *q2 + R2 ; R2 = b - q2 * R1 ;
R1 = R2 * q3 + R3 ; R3 = R1 - q3 * R2 ;
R2 = R3 * q4 + R4 ;
。。。。。。
值得注意的是右边的式子。可以发现每一个 R 都可以表示成 a 和 b 的倍数(把R1记作 (1,-q1)),可以定义一个结构体 A, B(好吧,是两个),
A.x ,A.y 分别表示 a, b 的系数,初始化一下A = a = (1,0),B = b = (0,1), 那么,R1 = A - q1*B ; 可以看到下面还要用到R1,而且用不到 A 了,
直接 令 A = R1 多好呢! A = A - B*q1 ; 再看R2 , R2 = B - q2*R1 = B - q2*A ; 同样 令 B = R2;则 B = B - A*q2;下面 R3 = A - q3*B ;也就是
A = A - q3*B ;再接着: B = B - A*q 。。。。。。等等,什么时候终止呢?在“再看R2"之前,考虑这样一个问题,若 R1 == g 呢?显然这个时候就要终止了,伪代码如下:
while(1) {
q = a/b;
r = a%b;
A = A - B*q;
(a,b) = (b,a%b);
(A,B) = (B,A) //这样更容易写代码
if (a%b == 0) break;
}
: 0 需特判。
代码如下:
1 void sol(int a,int b,int &g) 2 { 3 A.x = B.y = 1 ; 4 A.y = B.x = 0 ; 5 if (a == 0) { 6 g = b ; 7 A.x = 1; 8 A.y = 0; 9 return ; 10 } 11 if (b == 0) { 12 g = a; 13 A.x = 0; 14 A.y = 1; 15 return ; 16 } 17 Node C ; 18 int q, r ; 19 while (1) { 20 q = a/b ; 21 r = a%b ; 22 A.x = A.x - B.x*q; 23 A.y = A.y - B.y*q; 24 a = b; 25 b = r; 26 if (a%b == 0) break; 27 C = A; 28 A = B; 29 B = C; 30 } 31 g = b ; 32 }
其实呢?还有一个代码比较简短,用的是递归,附上如下:
1 void ex_gcd(int a,int b,int &g,int &x,int &y) 2 { 3 if (!b) { 4 g = a; 5 x = 1; 6 y = 0; 7 } 8 else { 9 ex_gcd(b,a%b,g,y,x) ; 10 y -= x*(a/b) ; 11 } 12 }
显然, a*x+b*y = gcd(a,b)的解不止一个((x,y)),事实上,此方程的每一个解都可由 (x+k*(b/g),y-k*(a/g))得出,其中 k 可取任意整数。