扩展欧几里得算法应用

1.扩展欧几里得算法

扩展欧几里得算法用来解决这样一个问题:

给定两个非零整数a,b,求一组整数解(x,y),使得ax+by=gcd(a,b)成立

对于gcd,考虑使用欧几里得算法,也就是辗转相除法,临界条件是当b=0,此时a的值就是gcd的值,即此时a*1+b*0=gcd(a,b)成立

int gcd(int a,int b)
{
    return !b?a:gcd(b,a%b);
}

假设当计算gcd(a,b)时,有ax1+by1=gcd成立;而在下一步计算gcd(b,a%b)时,又有bx2+(a%b)y2=gcd。因此ax1+by2=bx2+(a%b)y2成立。考虑到a%b=a-(a/b)*b,那么ax1+by1=bx2+(a-(a/b)*b)y2成立,整理可得ax1+by1=ay2+b(x2-(a/b)y2),可解出结果为,

\begin{cases} & \text x1=y2\\ & \text y1=x2-(\frac{a}{b})y2 \end{cases}

由以上分析,我们可以通过反推来获得x1,y1,于是我们只需得到边界情况即可利用递归得到最初情况下要求的x,y;

int exGcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1;
		y=0;
		return a;
	}
	int g=exGcd(b,a%b,x,y);
	int temp=x;
	x=y;        //更新
	y=temp-a/b*y;
	return g;    //g是gcd
}

这样,我们就得到的第一组解,同时可以通过下面式子得到通解:

\begin{cases} & \text x`=x+\frac{b}{gcd}*K\\ & \text y`=y-\frac{a}{gcd}*K \end{cases}

证明如下:

假设新的解为x+s1,y-s2,即有a*(x+s1)+b(y-s2)=gcd,联立ax+by=gcd得as1=bs2,于是\frac{s1}{s2}=\frac{b}{a},为了让s1和s2尽可能小,可以通过除一个尽可能大得数同时保证它们仍是整数。显示,gcd符合,于是\frac{s1}{s2}=\frac{b}{a}=\frac{b/gcd}{a/gcd},也就是说s1和s2得最小取值整数时b/gcd  和a/gcd。

也就是说,x和y的所有解,分别以b/gcd 和 a/gcd 为周期。

在考虑解的最小非负整数,只对x'分析,由于计算出来的x可能是负数,所有x'的最小非负整数为

(x%\frac{b}{gcd}+\frac{b}{gcd})%\frac{b}{gcd}

2.方程ax+by=c求解

利用1的算法,我们可以求解ax+by=c,c为任意整数。

 首先ax+by=gcd,假设由exGcd()得到的解为(x0,y0)。两边同时乘以c/gcd,即得到a\frac{cx}{gcd}+b\frac{cy}{gcd}=c,那么\left ( \frac{cx0}{gcd},\frac{cy0}{gcd} \right )是ax+by=c的一组解。

同时注意因为我们求得是整数解,所以这样做成立得充要条件是c%gcd==0。

同样根据1得通解求法,我们发现最后还是有\frac{s1}{s2}=\frac{b}{a},最后的通解为

\begin{cases} & \text x`=\frac{cx0}{gcd}+\frac{b}{gcd}*K\\ & \text y`=\frac{cy0}{gcd}-\frac{a}{gcd}*K \end{cases}

同样考虑最小非负整数解,只对x'分析

(\frac{cx0}{gcd}%\frac{b}{gcd}+\frac{b}{gcd})%\frac{b}{gcd}

3.同余式ax=c(mod m)的求解

 同余式,对于整数a,b,m来说,如果(a-b)%m=0,那么就说a与b模m同余,对应的同余式为a=b(mod m)。

根据同余式的定义,有(ax-c)%m=0成立。因此存在整数y使得ax-c=my,移项并令y=-y,得ax+my=c .

这样也就变换为 2得问题。

考虑到对同余式来说,虽然x有很多解,但很多解在模m的情况下意义是相同的。

于是对于x`=\frac{cx0}{gcd(a,m)}+\frac{m}{gcd(a,m)}*K  ,当K=0,1,2......gcd(a,m)-1时,所得到的解在模m下的意义是不同的,而其他解都可以在这里取到对应的值。

证明如下:

x'%m,只需考虑\frac{m}{gcd(a,m)}*K这一部分模m的影响。变换形式\frac{K}{gcd(a,m)}*m,可以看到如果K>=gcd(a,m),那么分数可以转换位一个整数+一个小于0的分数,其中整数部分*m对m取余是没有意义的。

 4.逆元的求解

 逆元(此处特指乘法逆元),假设a,b,m是整数,m>1,具有ab=1(mod m)成立,那么就说a和b互为模m的逆元,一般也记为a=1/b(mod m)或 b=1/a(mod m)。

通俗的说,如果两个数的乘积模m后等于1,那么ab互为m的逆元。(逆元的定义是同余式的一个特殊情况,即c=1).

逆元的作用

对于除法,(b/a)%m=((b%m)/(a%m))%m是不成立的,当b非常大时,直接计算是不实用的。

我们可以利用逆元,消除被除数a也就消除了除法。所以 找到a模m的逆元x,就有 (b/a)%m=(b*x)%m成立。

由定义可知,求x也就是解同余式ax=1(mod m),并且在实际应用中选x的最小正整数解作为所求x.

根据3,也就是求ax+my=1,这里我们注意到因为1%gcd(a,m)=0,所以gcd(a,m)=1,所以我们只需求的x得一个解后,利用公式直接得逆元.

int inverse(int a,int m)
{
    int x,y;
    int g=exGcd(a,m,x,y);
    return (x%m+m)%m;
}

 

如果m是素数,且a不是m的倍数,可以直接使用费马小定理来得到逆元。

费马小定理:设m是素数,a是任意整数且a不是m的倍数,则a^{m-1}=1(mod m).

所以a模m的逆元是a^{m-2}%m

 

 

如果gcd(a,m)!=1,那么就不能用逆元的方法。

假设(b/a)%m=x,因此存在整数k,使得b/a=km+x,即b=kma+ax,于是有b%(ma)=ax,于是有(b%(ma))/a=x=(b/a)%m。

所以可以使用该公式求,可能的问题是am可能溢出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值