拓展欧几里得算法是用来解决不定方程的整数解的算法
最大公因数
众所周知,辗转相除法是解决两个数a,b的最大公因数的方法,记作gcd(a,b)
每次用a MOD b ,然后将b和模得的数再继续模下去,知道模数为0,也就是b|a
写成代码是:
int gcd(int a,int b){
retrun b==0 ? a:gcd(b,a%b);
}
很简短吧
拓展欧几里得算法
现在才是本文的重点
对于一个关于x和y的方程ax+by=c,我们知道这是一个不定方程,也就是说它的解不唯一
我们只研究整数解的情况,那么这个方程要么没有整数解,要么有无数个整数解
如何解?
1、求解ax+by=gcd(a,b)
本人很弱,不会证明,所以只给出过程。
在gcd过程中,当b=0时,x=1,y=0
否则x=y',y=x'-(a/b)*y'
这里的除法为整除
下面是实现代码:
void exgcd(int a,int b,int& d,int& x,int& y){
if(b==0){d=a;x=1;y=0;}
else exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}
我们发现,当上一个方程进行这个操作之后,就会变成我们想要的方程的形式
a*x*c/gcd+b*y*c/gcd=c
为了保证整数,当c%gcd!=0时,方程无整数解
若有解,x=x*c/gcd,y=y*c/gcd
3、解的周期
令b0=b/gcd,a0=a/gcd;
那么
x'=x+k*b0
y'=y-k*a0
就是所有的解
其中x的最小整数解是(x%b0+b0)%b0
完整求x最小整数解代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
void exgcd(int a,int b,int& d,int& x,int& y){
if(!b) {d=a;x=1;y=0;}
else exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}
int main()
{
int a,b,c,x,y,b0,d;
cin>>a>>b>>c;
exgcd(a,b,d,x,y);
if(c%d) cout<<"No solution!"<<endl;
else{
x=x*c/d;
b0=b/d;
cout<<(x%b0+b0)%b0<<endl;
}
return 0;
}