1.欧几里德算法-辗转相除法求最大公约数
int gcd(int a,int b)
{
return b?gcd(b,a%b):0;
}
证明:
1.当b=0时,a,b最大公约数为a.显然成立
2.当b不为0时,gcd(a,b)=gcd(b,a%b)
令d为a,b的一个约数,则 d|a,d|b (a整除d,b整数d)
令r=a%b,根据模的定义 r=kb+a (k为整数) ,则 d|r
因为 b整除d,a%b也整除d,所以d也是b,a%b的约数
所以a,b的约数和b,a%b的约数是相同的,自然他们的最大公约数也是相同的,证明成立
2.扩展欧几里德算法-求模线性方程 ax+by=gcd(a,b)
/*
* 对于不全为0的非负整数a,b,必然存在一组整数x,y使得ax+by=gcd(a,b) 成立
* 注意:a,b必须为非负整数
*/
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
int r=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return r;
}
证明:
1.当b=0时,gcd(a,b)为a,则x=1,y=0,ax+by=a=gcd(a,b),显然
2.当b不为0时
因为gcd(a,b)=gcd(b,a%b)
所以a*x1+b*y1=b*x2+(a%b)*y2
又因为a%b=a-a/b*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,y2是基于x2,y2的,所以只要求得x2,y2即可知x1,y1! 程序中我们通过迭代实现, 直迭代到b=0为止,返回x2=1,y2=0,然后再一步一步返回,即可求的x1,y1! 证明完毕
3.扩展欧几里德算法的应用
1.不定方程的求解
对于不定整数方程 ax+by=c ,若c%gcd(a,b)=0,则方程有解,否则无解
求解步骤: 一 先利用扩展欧几里德求的一组解(x,y)使得a*x+b*y=gcd(a,b) 则ax++by=c的一组特解为 x1=x*k,y1=y*k (k=c/gcd(a,b))
二 求出特解后,通解则为 x=x1+b1*t (b1=b/gcd(a,b) ,t为任意整数)
y=y1-a1*t (a1=a/gcd(a,b),t为任意整数)
一般题目中要求最小的非负整数x,y使得ax+by=c成立,再求得特解x1,y1后,我们可以直接通过 x=(x1%b1+b1)%b1 y=(y1%a1+a1)%a1求得 (a1,b1含义同上)
模版:
# define LL long long
LL d
/*
*扩展欧几里德算法
*ax+by=gcd(a,b)
*/
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
LL r=exgcd(b,a%b,x,y);
LL t=x;
x=y;
y=t-a/b*y;
return r;
}
/*
*函数功能 求ax+by=c一组特解,特解存储在x,y中 有解返回1,无解返回0
*注意点 1: 必须满足a,b>=0
* 2: gcd(a,b)=d 存储在d中
* 3: 若求最小正整数x使得ax+by=c,求得特解后 x=(x%b1+x)%b1 b1为b/gcd(a,b)
* 4: 若求最小正整数y使得ax+by=c,求得特解后 y=(y%a1+y)%a1 a1为a/gcd(a,b)
*/
bool liner_equation(LL a,LL b,LL c,LL &x,LL &y)
{
d=exgcd(a,b,x,y);
if(c%d)
return 0;
LL k=c/d;
x*=k;y*=k;
return 1;
}
2.不定方程的求解