关于exgcd(扩展欧几里得定理):
由扩展欧几里德定理,可以通过扩展欧几里德算法求解线性同余方程
扩展欧几里德定理(百度百科)
对于不完全为 0 的整数 a,b,gcd(a,b)表示 a,b 的最大公约数。那么一定存在整
数 x,y 使得 gcd(a,b)=ax+by。
即 ax +by = gcd(a, b); 一定存在整数解(x, y);
题设:
已知a,b,设方程组:ax + by = gcd(a, b) , 求一组(x, y)使得该式成立。
推导过程:
由欧几里得定理可知:
由:ax1+by1 = gcd(a, b) = gcd(b, a%b) = bx2 + (a%b)y2 ;
而 :bx2 + (a%b)y2 = bx2 + (a - a/b * b)y2 ;
整理可得:
x1a + y1b = y2a + (x2 - a/b*y2)b
由a, b的系数相同和待定系数法可知:
x1 = y2;
y1 = x2 - a/b*y2;
这样它就将a与b的线性组合化简为b与a%b的线性组合。
因为a和b都在不断减小,gcd(a, b) = gcd(b, a%b) 当b==0 时,a即为gcd(a, b);
所以,当b == 0;时,存在递归终点,此时,xn=1, yn=0;
然后递归回去就可以求出最终的x1和y1了
代码:
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
int gcd = exgcd(b, a%b, x, y);
int t = x;
x = y;
y = t-a/b*y;
return gcd;
}
解出的(x1, y1)为ax + by = gcd(a, b)的一组解。
题设:
已知a,b,c,设方程组: ax + by = c, 求一个最小正整数解x,使得该方程成立。
推导过程:
由上述扩展欧几里得定理可知:c = n*gcd(a, b) (n为整数)
即原式变为:ax + by = gcd(a, b) *n (n为整数)。[即n = c/gcd(a, b)]
由上个题设exgcd可求得一组解(x1, y1)
即求得一组(x1, y1)使得 :
ax1 + by1 = gcd(a, b) ------------------------------------------------ (1)
令gcd = gcd(a, b);
因为gcd = gcd(a, b) 所以, a*x1/gcd是整数,b*y1/gcd是整数, 所以c/gcd也需要是整数,否则无解。
让上述(1)式两边都乘(c/gcd)
得到:a*(x1*(c/gcd)) + b*(y1*(c/gcd)) = gcd * (c/gcd)
化简得:a*(x1*(c/gcd)) + b*(y1*(c/gcd)) = c -------------------------- (2)
即原式中的解(x, y)可有exgcd后的一组解(x1, y1)表示为:
x = x1*(c/gcd)
y = y1*(c/gcd)
此时的x1*(c/gcd)是最小的解,但有可能是负数。
因为 a*(x1*(c/gcd) + b*n) + b*(y1*(c/gcd) - a*n) = c (n是自然数)
所,x的最小正整数解为:
x = (x1*(c/gcd)%b+b)%b
反过来可得最小的y的正整数解为:
y = (y1*(c/gcd)%a+a)%a
这里给出一个为什么x = (x1*(c/gcd)%b+b)%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;
}
int main()
{
int a, b, c;
while(cin >> a >> b >> c && a+b+c)
{
int x, y;
int z = exgcd(a, b, x, y);
cout << x << ' ' << y << ' ' << z << '\n';
x*=c/z; //一组解x,y
y*=c/z;
cout << x << ' ' << y << '\n';
int t = b/z; //求ax+by = c 的最小正整数x,b/z是(2)式约掉c之后的。。
x = (x%t+t)%t;
y = abs((a*x - c)/b);
t = a/x; //求ax+by = c 的最小正整数y
y = (y%t+t)%t;
x = abs((b*y - c)/a);
cout << x << ' ' << y << '\n';
}
return 0;