【數論】拓展歐幾里得演算法
寫在前面
這篇部落格是我在【數論】對 算術基本定理 的研究 中的一部分
- 拓展歐幾里得演算法
現在已經有了a-b == GCD(a,b) * (n1-n2),那就可以再來個直接點的
GCD(a,b) + (p*n1+q*n2) == GCD(a,b)
此處放到MOD群裡面可以變形為求逆元素
即p*a+q*b == GCD(a,b)
想要求出一組p,q∈Z,滿足上式
首先套用歐幾里得演算法的邏輯:
結合算術基本定理,有
GCD(a,b) == P1min(a1,b1)
a MOD b == P1a1-b1P2a2-b2......Pnan-bn(執行的條件為ai>=bi)
則能得到GCD(a,b) == GCD(b,a MOD b)
那麼就有p*a+q*b == GCD(a,b) == GCD(b,a MOD b)
這樣就可以寫一個遞迴函式,一層一層MOD下去
這樣化簡,直到ai MOD bi == 0
即p*GCD(a,b) == GCD(a,b),那麼在最後一層裡面p==1
所以在拓展歐幾里得裡面,bi==0這一層中,ai即為GCD(a,b)
(到此為止和歐幾里得演算法一模一樣,我甚至是複製的歐幾里得演算法)
而如果想要求出p和q,那麼有一個回溯的過程就好了
如何回溯得到p和q呢?
來找一下相鄰的層數間pi和pi+1,qi和qi+1的關係
因為有p*a+q*b == GCD(a,b)
則在每一層中:
GCD(a,b)
== pi*a+qi*b
== pi+1*b + qi+1*(a MOD b)
== pi+1*b + qi+1*(a - (a/b)*b)
== pi+1*b + qi+1*a - qi+1*(a/b)*b
== qi+1*a + pi+1*b - qi+1*(a/b)*b
== qi+1*a + (pi+1 - qi+1*(a/b))*b
即每層中pi == qi+1,qi == pi+1 - qi+1*(a/b)
然後就可以回溯了!
然後就能寫出不返回gcd,單純求出一組p,q的拓展歐幾里得了!
C++:
1 #include<bits/stdc++.h> 2 #define OUT(x) cout<<#x<<":"<<x<<endl; 3 4 using namespace std; 5 6 int x,y; 7 8 void exgcd(int a,int b) 9 { 10 if(!b){x=1;y=0;} 11 else{ 12 exgcd(b,a%b); 13 int tmp=x; 14 x=y;y=tmp-(a/b)*y; 15 } 16 } 17 18 int main(int argc,char *argv[],char *enc[]) 19 { 20 exgcd(12,17); 21 OUT(x);OUT(y); 22 return 0; 23 }
上面這個版本是我寫的,比較詭異,來個常見的版本
C++:
1 #include<bits/stdc++.h> 2 #define OUT(x) cout<<#x<<":"<<x<<endl; 3 4 using namespace std; 5 6 int x,y; 7 8 int exgcd(int a,int b) 9 { 10 if(!b){ 11 x=1;y=0; 12 return a; 13 } 14 int ret=exgcd(b,a%b); 15 int tmp=x; 16 x=y;y=tmp-(a/b)*y; 17 return ret; 18 } 19 20 int main(int argc,char *argv[],char *enc[]) 21 { 22 OUT(exgcd(12,17)); 23 OUT(x);OUT(y); 24 return 0; 25 }
仔細感受一下其中的差別啦~