欧几里德和扩展欧几里德详解 以及例题CodeForces 7C
欧几里德定理:
对于整数a,b来说,gcd(a, b)==gcd(b, a%b)==d(a与b的最大公约数),又称为辗转相除法
证明:
因为a是d的倍数,b是d的倍数;所以a%d==0;b%d==0;
设k=a/b;r=a%b;则 a=k*b+r;
由上得出:r=a-k*b;
因为a和b都是d的倍数,所以(a-k*b)也是d的倍数,所以r也是d的倍数;
所以gcd(a, b)==gcd(b, a%b)==d
而为什么要证明gcd(a, b)==gcd(b, a%b)==d这个式子成立呢?
其实证明gcd(a, b)==gcd(a, a%b)==d这个式子成立也是可以的,因为a也是d的倍数,但是在进行递归之前要进行一步操作,就是判断a与b的大小,如果a<b,就没办法进行递归或者循环求最大公约数,那么如果a<b,就交换a与b,之后就不用交换了,因为已知a>b,那么a%b<a必定成立;
事实发现证明gcd(a, b)==gcd(b, a%b)==d这个式子会缩小处理的数据的范围;
欧几里德应用:
用来求a,b的最大公约数。
代码实现:
//gcd(a, b)==gcd(a, a%b)==d,也成立 #include<stdio.h> int main() { int m, n, r, t; scanf("%d%d", &m, &n); if(m<n) { t=m; m=n; n=t; } while(r=m%n, r!=0) { m=m; n=r; } printf("%d\n", n); return 0; }
//gcd(a, b)==gcd(a, a%b)==d递归 int gcd(int m, int n) { return n?gcd(n, m%n):m; }
//gcd(a, b)==gcd(a, a%b)==d递归
int gcd(int m, int n) { if(m%n==0) return n; else return gcd(n, m%n); }
//gcd(a, b)==gcd(b, a%b)==d 循环 while((r=m%n)!=0) { m=n; n=r; }
扩展欧几里德定律:
对于不完全为0的非负整数a,b;gcd(a, b)表示a, b的最大公约数,必定存在整数对x,y,满足a*x+b*y==gcd(a, b);
证明:
a*x1+b*y1=gcd(a, b);
b*x2+(a%b)*y2=gcd(b, a%b);
因为由欧几里德定理知:gcd(a, b)==gcd(b, a%b)
所以a*x1+b*y1=b*x2+(a%b)*y2; 因为r=a%b, r =a-k*b所以==>
a*x1+b*y1=b*x2+(a-k*b)*y2; 因为k=a/b;所以 ==>
a*x1+b*y1=b*x2+(a-(a/b)*b)*y2; 展开得到 ==>
a*x1+b*y1=b*x2+a*y2-b*(a/b)*y2; 转换得到 ==>
a*x1+b*y1=a*y2+b*(x2+(a/b)*y2);
观察上式可知 x1=y2, y1=x2-a/b*y2;
由此可知x1,y1是由x2,y2得出来的,由此类推x2,y2是由x3,y3得出来的,
那什么时候是终止呢?也就是递归gcd(a, b)中b=0时;也就是说此时a的值就是要求得最大公约数
即gcd(a, 0)此时由扩展欧几里得定律a*x+b*y==gcd(a, b)知 a*x+b*y=a;
解出x=1, y=0;
此时就是递归终止的地方:
扩展欧几里德应用:
就我目前所知的就是:求解不定方程;如a*x+b*y=c; 已知a, b, c的值求x和y的值
那么问题来了,如何将扩展欧几里德定律应用在求解不定方程呢?
可以这样转化 a*x+b*y=gcd(a, b)*c/gcd(a, b);
最后转化为 a*x/(c/gcd(a, b))+b*y/(c/gcd(a, b))=gcd(a, b); 最后求出的解x0,y0乘上c/gcd(a, b)就是最终的结果了
x1=x0*c/gcd(a, b);
y1=y0*c/gcd(a, b);
代码实现: 举例说明:http://codeforces.com/problemset/problem/7/C
#include<stdio.h> long long exgcd(long long a, long long b, long long &x, long long &y); int main() { long long a, b, c, ans, x, y; while(scanf("%lld%lld%lld", &a, &b, &c)!=EOF) { ans=exgcd(a, b, x, y); if(c%ans==0) { x=-x*c/ans; y=-y*c/ans; printf("%lld %lld\n", x, y); } else printf("-1\n"); } return 0; } long long exgcd(long long a, long long b, long long &x, long long &y) { if(b==0) { x=1; y=0; return a; } long long r=exgcd(b, a%b, x, y), t; t=x; x=y; y=t-(a/b)*y; return r; }
但这只是求得了一组解x1,y1
对于x,y对应的解集是:
x=x1+b/gcd(a, b)*t;
y=y1-b/gcd(a, b)*t;
但是我证明不出来,如果哪位大神懂得,可以给我说说!