關於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;