浅谈扩展欧几里得算法

什么是拓展欧几里得?简单的说,就是求关于x,y的方程 ax + by = gcd(a,b) 的所有整数解


现在我们来解决一下三个问题

  • 怎么求上述方程的特解?
  • 怎么求由特解推出其他的所有解?
  • 如何求的是ax + by = c,则解为什么?

一、求特解

我们都知道,欧几里得公式可以由这个式子表达

gcd(a, b) = gcd(b, a % b)

通过这个式子,我们可以不断递推到b = 0, 此时a即为a和b的最大公约数

现在我们对这个式子进行展开,看看有什么好玩的嘛

gcd(a, b) = a * x1 + b * x2

gcd(b, a % b) = b * x2 + (a % b) * y2

其中a % b = a - (a / b) * b

故由第一行的欧几里得公式得:

a * x1 + b * y1 = b * x2 + {a - (a / b) * b}y2

化简得a * x1 + b * y1 = a * y2 + b * {x2 - (a / b) * y2}

根据待定系数法得到

  • x1 = y2

  • y1 = x2 - (a / b) * y2

也就是说,如果有了gcd(b, a % b)的解x2, y2就可以推出gcd(a, b)的解x1, y1

那么这就和求gcd的过程一样,一直推到最后x = 1, y = 0,就可以回溯回去,得到gcd(a, b)的特解x1, y1

特解其实是最小的一个解

二、怎么利用特解推出其他所有整数解

先说结论:

x = x 0 + k ∗ b g c d ( a , b ) x = x0 + k * \frac{b}{gcd(a,b)} x=x0+k∗gcd(a,b)b​

y = y 0 − k ∗ a g c d ( a , b ) y = y0 - k * \frac{a}{gcd(a,b)} y=y0−k∗gcd(a,b)a​

x0, y0就是方程的特解

对于a * x + b * y = g来说,让x增加b/gcd,让y增加a / gcd

这样就相当于加a * b / gcd,减去a * b / gcd,一加一减,最终不变

三、如何求的是ax + by = c,则解是什么?

如果 c % gcd(a, b) == 0,即c 是 gcd(a, b)的整数倍,则方程有解,且解就在上面的基础上乘以 c g c d ( a , b ) \frac{c}{gcd(a, b)} gcd(a,b)c​即可

void e_gcd(int a, int b, int &gcd, int &x, int &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        gcd = a;
    }
    else
    {
        e_gcd(b, a % b, gcd, y, x);
        y -= x * (a / b);
    }
}

int main(){
    int a, b, x, y, gcd;
  	cin>>a>>b;
    e_gcd(a, b, gcd, x, y);
    cout<<x<<' '<<y<<endl;
    cout<<gcd<<endl;
    return 0;
}

参考博客

上一篇:[算法总结] 差分


下一篇:Python基础之数据可视化