拓展欧几里得算法是用来解决不定方程的整数解的算法
最大公因数
众所周知,辗转相除法是解决两个数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; }