数论——扩展欧几里得算法(exgcd)

求不定方程 a∗x+b∗y=1 的一组解的方法
由 a∗x1+b∗y1=gcd(a,b)=gcd(b,amod b)=b∗x2+[a−⌊a/b⌋∗b]∗y2=a∗y2+b∗(x2−y2∗⌊a/b⌋)

=>x1=y2
=>y1=x2−y2∗(a / b)
 

用途:
1)求解不定方程;
2)求解模线性方程(线性同余方程);
3)求解模的逆元;

1)求解不定方程

利用扩展欧几里得算法求解不定方程a∗x+b∗y=n的整数解的求解全过程,步骤如下:

(1)先计算Gcd(a,b),若n不能被Gcd(a,b)整除,则方程无整数解;否则,在方程两边同时除以Gcd(a,b),得到新的不定方程a2∗x+b2∗y=n2此时Gcd(a2,b2)=1;

(2)利用扩展欧几里德算法求出方程a2∗x+b2∗y=1的一组整数解x0,y0,则n2∗x0,n2∗y0是方程a2∗x+b2∗y=n2的一组整数解;

(3)根据数论中的相关定理,可得方程a2∗x+b2∗y=n2的所有整数解为:
x=n2∗x0+b2∗t
y=n2∗y0−a2∗t (t=0,1,2,……)
调整得到正整数解
LL exgcd(LL a, LL b, LL &x, LL &y) {  
    if(!b) {  
        x = 1;  
        y = 0;  
        return a;  
    }  
    LL ans = exgcd(b, a%b, x, y);  
    LL temp = x;  
    x = y;  
    y = temp - a / b * y;  
    return ans;  
}  
LL cal(LL a, LL b, LL c) {  
    LL x, y;  
    LL gcd = exgcd(a, b, x, y);  
    if(c % gcd != 0) return -1;  
    x *= c / gcd;  
    b /= gcd;  
    if(b < 0) b =- b;  
    LL ans = x % b;  
    if(ans <= 0) ans += b;  
    return ans;  
} 

数学一本通:注释此代码来自课本,未经测试,编译没问题

/*ax+by=GCD(x,y)->ax+(x-a/b*q)*b正向递归,返回时相应元素一一对应   */

#include<cstdio>//ax+by=GCD(a,b)
using namespace  std;
int extended_gcd(int a, int  b, int &x, int &y)
{
	int ret,temp;
	if (!b)
	{
		x = 1;
		y = 0;
		return a;//整个的最终函数返回的的值,最大公约数
	}
	extended_gcd(b, a%b, x, y);
	temp = x;
	x = y;
	y = temp - a / b * y;
	return ret;//递归逐步返回的公约数
}
int main()
{
	int a, b, x, y, z;
	scanf("%d%d", &a, &b);
	z = extended_gcd(a, b, x, y);
	printf("%d%d%d", z, x, y);//输出最大公约数和一组解
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sunpeishuai/article/details/81289124