详细讲解【拓展欧几里得】
exgcd(拓展欧几里得)
1.回顾辗转相除法求最大公倍数:
(辗转相除法和下面所讲到的算法里面的m和n没什么关系可正可负 更没有大小关系的区分)
代码:
#include<stdio.h>
int gcd(int a,int b)
{
int temp;
if(b==0){
return a; // b=0 满足关系跳出循环,此时a的值就是最大公约数
}
return gcd(b,a%b);
}
int main()
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",gcd(a,b));
return 0;
}
2.exgcd:
a.求二元一次方程的一组特解:
原理:
•ax+by=gcd(a,b)
•∵ gcd(a,b) = gcd(b,a%b)
•∴ ax1+by1 = bx2+(a%b)y2 //可以知道 a在被替换成了b,b被替换成了a%b
•则 ax1+by1 = bx2+(a-a/b*b)y2
•∴ ax1+by1 = ay2+b(x2-a/b*y2)
•∴ x1=y2 y1=(x2-a/b*y2) //这一步的x等于上一步的y,y等于(x2-a/b*y2) x2 y2 代表上一步的x和y
•当b==0时,ax+by = gcd(a,b) = a
•∴ x=1 , y=0;
代码:
#include<stdio.h>
int GCD;
int gcd(int a,int b,int &x,int &y) //&x 类似于指针在c++函数调用中可以将x的值改变
{
if(!b){ ②
x=1;y=0;return a;
} //调用的函数运行顺序
GCD=gcd(b,a%b,y,x); ① //调用函数时的&不能加,错误不太容易发现
y-=a/b*x; 3 4 ...
return GCD; //最后返回的GCD的含义其实就是a和b的最大公约数
}
int main()
{
int a,b,x,y;
scanf("%d%d",&a,&b);
GCD=gcd(a,b,x,y);
printf("%d %d %d",x,y,GCD);
return 0;
}
b.求通解:
•ax + by = gcd(a,b) 的解集
•首先可以肯定它一定有解且解的数量无限
•我们可以找出式子可以加减的最小元 即最小公倍数lcm
•若x +- b/gcd y-+ a/gcd 则等式依然成立 //如果x后为+ 则y后为-
•便可得知解集
c.判断ax+by=c是否有解:
只要c为gcd(a,b)的倍数,就有无数组结
例: 38x+8y=gcd(38,8)=2; ①
如果此时c=6 即:38x+8y=6; ②
计算②式特解的方法: 先算出①式的特解 然后将x和y同时乘于6 / gcd(38,8)就能得到一组特解;
d.求最小整数解:
//用于解决ax+by=c类的求最小整数解
GCD=exgcd(a,b);
x=c/GCD; //如果非上面的类型而直接是=gcd(a,b) 可将这一步去掉即可
t=b/GCD:
if(t<0){
t=-t; //防止b/GCD为负数
}
x=(x%t+t)%t;
e.综合例题:青蛙的约会(点击)