1.1.3 最大公约数
主要内容:辗转相除法、二进制算法、最小公倍数、扩展欧几里得算法、求解线性同余方程
一、 辗转相除法
辗转相除法也称欧几里得算法。在稍后,我们会学到扩展欧几里得算法,其是在欧几里得算法的基础上发展的。
下面给出代码,相关证明可以参考《高等代数》第一章多项式中求最大公因式的证明
int gcd(int x, int y){
if (x0) return y;
if (y0) return x;
return gcd(y,x%y);
}
点击并拖拽以移动
二、 二进制算法
一般的辗转相除法效率较低,下面给出利用因数2优化的辗转相除法。
inline int gcd(int x, int y){
if (x0) return y;
if (y0) return x;
int i,j,k;
for (i=0;(x&1)0;i++) x>>=1;//除去x中所有因子2
for (j=0;(x&1)0;j++) y>>=1;//除去y中所有因子2
k = min(i,j);//算出公共因子2的次数
while(1){
if (x<y) swap(x,y);
if ((x-=y)0) return y<<i;
while ((x&1)0) x>>=1; //去掉冗余的因子2
}
}
点击并拖拽以移动
根据我的理解,2也可以更换为其他的因数,从而产生相似的算法,但二进制算法的优势在于,其有因子2,二进制移位运算相较四则运算和取模运算较为快速,因此我们采用二进制算法
三、最小公倍数
易证下面的结论
\[a\cdot b = (a,b) \cdot [a,b]\\ 其中(a,b)表示a和b的最大公约数,[a,b]表示a,b的最小公倍数\\ 从而有\\ [a,b] = \frac{ab}{(a,b)}\\
\]
四、 扩展欧几里得算法
首先,我们应当了解一个著名的定理:
裴蜀定理
\[\begin{aligned} 对a,b\in \mathbb{Z},(a,b) = d\quad&\Leftrightarrow\quad\exists x,y\in\mathbb{Z}\quad\quad ax+by = kd\quad(k\in \mathbb{Z}-\big\{0\big\})\\ 特别地,令k=1:(a,b) = d\quad&\Leftrightarrow\quad\exists x,y\in\mathbb{Z}\quad s.t.ax+by=d\\ 推论,当k=d=1:(a,b)=1\quad&\Leftrightarrow\quad\exists x,y\in\mathbb{Z}\quad s.t.ax+by=1 \end{aligned}
\]
我们主要考察第二个等式
对于给定的a,b,我们可以通过欧几里得算法求得d
但是如何求出对应的p,q,使得pa+qb=d呢?
这就需要用到扩展欧几里得算法。
下面先给出推导过程
\[\begin{aligned} 由(a,b)=d,可设p_1a+q_1b&=d\\ 再由(b,a\%b)=d,可设p_2b+q_2(a\%b)&=d\\ 令t=[\frac{a}{b}],则a\%b&=a-bt\\ 即p_2b+q_2(a-bt)&=d\\ 乘开后合并得q_2a+(p_2-q_2t)b&=d\\ \end{aligned} \begin{aligned} 于是,p_1&=q_2\\ q_1&=p_2-q_2t=p_2-q_2[\frac{a}{b}]\\ 于是,我们找到了(p_1,q_1)&与(p_2,q_2)的关系,\\ \quad\quad我们可以将其作为递归公式使用:\\ (p_n,q_n)&=(q_{n+1},p_{n+1}-q_{n+1}[\frac{a_n}{b_n}]) \end{aligned}
\]
再考虑边界条件:
\[a_n\ne0,b_n=0\left\{ \begin{matrix} p_n=1 \\ q_n=0 \end{matrix} \right.\\ a_n=0,b_n\ne0\left\{ \begin{matrix} p_n=0 \\ q_n=1 \end{matrix} \right.\\
\]
于是,我们得到了下面的算法
\[如果a_n\ne0,b_n=0\left\{ \begin{matrix} \begin{aligned} (p_n,q_n)&=(1,0) \\ gcd(a_n,b_n)&=a_n \end{aligned} \end{matrix} \right.\\ 如果a_n=0,b_n\ne0\left\{ \begin{matrix} \begin{aligned} (p_n,q_n)&=(0,1) \\ gcd(a_n,b_n)&=b_n \end{aligned} \end{matrix} \right.\\ 否则,令(a_{n+1},b_{n+1})=(b_n,a_n\%b_n)\left\{ \begin{matrix} \begin{aligned} (p_n,q_n)&=(q_{n+1},p_{n+1}-q_{n+1}[\frac{a_n}{b_n}])\\ gcd(a_n,b_n)&=gcd(b,a\%b) \end{aligned} \end{matrix} \right.\\ 其中,n可以理解为程序当前所在的递归层数\\
\]
将上述大括号内容的程序合并在一个函数中,我们就得到了扩展欧几里得算法
代码如下:
int exgcd(int a, int b, int &p, int &q){
//两种边界情况
if (!a){
p = 0, q = 1;
return b;
}
if (!b){
p = 1, q = 0;
return a;
}
//不处于边界情况,准备递归
int d = exgcd(b, a%b, p, q);//递推,回归时p,q的层数为n+1
int p2 = p, q2 = q; //存储第n+1层的p,q的信息
p=q2, q = p2 - q2 * (a / b);//计算第n层的p,q的信息;
return d; //返回gcd(a,b)
}
点击并拖拽以移动
五、求解线性同余方程
借助扩展欧几里得算法,我们可以求解线性同余方程
\[pa \equiv c \quad(mod\quad b)
\]
求解该方程等价于求解
\[pa + qb = c
\]
很显然,当c是d=(a,b)的倍数时,该方程有解。
于是此方程可用扩欧算法求解,
\[\begin{aligned} 先对p_0a+q_0b&=d解出p_0和q_0\\ 再设c&=kd=k\cdot(a,b)\\ 则kp_0a+kq_0b&=kd=c\\ 即p=kp_0&,q=kq_0 \end{aligned}
\]
bool linrequ(int a, int b, int c, int &p, int &q){
int d = exgcd(a, b, p, q);
if (c % d) return false; //如果c不整除d,则无整数解
int k = c / d;
p *= k; q *= k;
return true;
}
点击并拖拽以移动
需要注意的是,由于原同余方程中不存在q,所以同余方程中可能有多组解。
根据本原解p,q可以构造出更多的解
\[\begin{aligned} \forall t \in \mathbb{Z}\quad(p_n,q_n) &= (p+tb,q-ta)\quad\\ 都是方程\quad pa &\equiv c \quad(mod\quad b)\quad的解 \end{aligned}
\]
本文由“庞加莱复现”原创,未经允许,严禁转载!
如果觉得本文对你有用,不妨点赞收藏一下吧!