拡張ユークリッドの互除法を解説してみた
先日、こんな記事を書いた。
拡張ユークリッドの互除法を自己流で実装してみた。 - いろはすの競プロ反省会
これだけではあまりに不親切なので、ここに書いたコードの解説をしていこうと思う。
※上の記事に書いたコードは自己流で書いたものなので、蟻本に載っている拡張ユークリッドの互除法のコードとは異なります。予めご了承ください。また、ユークリッドの互除法については既知とします。
まず、拡張ユークリッドの互除法とは何かというと、0でない整数a,bに対して次の式を満たす整数x,yの組を求めるアルゴリズムである。
・・・(1)
ここで、はa,bの最大公約数である。 これはベズーの等式として知られる式であり、整数解が必ず存在する。
アルゴリズムの説明に入ろう。 まず、上の式においてとおく。
・・・(2)
ここで、
・・・(3)
(便宜上、剰余の記号として'%'を用いた)であるから、(3)を(2)に代入し、
・・・(4)
を得る。ここで、
・・・(5)
・・・(6)
・・・(7)
・・・(8)
とすると、式(4)は
・・・(9)
となる。ここで、式(7),(8)の変換をよく見ると、これはユークリッドの互除法で用いる変換と全く同じ変換である。従って、
・・・(10)
これを(9)に代入し、
・・・(11)
を得る。
式(11)と式(2)を見比べると、何と全く同じ形をしている! 以下、同様に
・・・(12)
・・・(13)
・・・(14)
・・・(15)
とすれば、次々に変換を続けていくことができる。
式(14),(15)の変換がユークリッドの互除法の変換と同じであることに注意すると、この操作はあるi=nで終了し、
となる。このとき、i=nに対応する等式は
であるから、その解は(例えば)、
・・・(16)
・・・(17)
である。 あとは、ここから(12),(13)の逆変換
・・・(18)
・・・(19)
を用いてこれまでの変換を逆に辿れば、元の式(2)の解が求まる。 この変換式(18),(19)こそがアルゴリズムの肝であり、それを実装したのが以下のコードである。
//xa+yb=gcd(a,b)の整数解を求める typedef pair<int,int> P; P extgcd(int a, int b){ if(b==0) return P(1, 0); P p = extgcd(b, a%b); int x = p.first; int y = p.second; return P(y, x - y*(a/b)); //逆変換(18),(19) }