zoukankan      html  css  js  c++  java
  • 扩展欧几里得

    窝们可以先来看一个式子:

    [ax + by = gc d(a,b) ]

    根据欧几里得可以得到:

    [gcd(a,b) = gcd(b, a \% b) ]

    不会欧几里得的同学们可以看这里

    又根据原式可以推出 :

    [gcd(b, a \% b) = b * x_1 + (a \% b) * y_1 ]

    所以可以得到:

    [a * x + b * y = b * x_1 + (a \% b) * y_1 ]

    再化简,得:

    [x * a + y * b = x_1 * b + (a - (frac{a}{b}) * b) * y_1 ]

    运用主元法,可得:

    [x * a + y * b = y_1 * a + (x_1 - frac{a}{b} * y_1) * b ]

    窝们把 (a, b) 当作元,再来重新来看这个问题。

    对于一个丢番图方程,(a * x + b * y = a_1 * x_1 + b_2 * y_1)

    是不是肯定会有这样一组解:(a = a_1)(b = b_2)

    那么原方程是不是肯定会有一个这样的根:

    [x = y_1 \ y = x_1 - frac{a}{b} * y_1 ]

    如果你可以理解上面这些步骤,那么你肯定可以知道这个 (x, y) 是可以递归求解的。只不过要处理一下 (-frac{a}{b} * y_1)

    那么,窝们先来看看代码怎么实现,说不定看完你就懂了。

    void exgcd(int a, int b, int &x, int &y) {
        if(b == 0) {x = 1, y = 0; return a;}//这个是一个必然存在的解,后面解释。
        exgcd(b, a % b, y, x);//这是不断递归,窝们前面对于y的变换法则中,窝们只管了x1,后面那个式子先不管他,至于前面这个a,b为什么要这样递归,是因为窝们转换原方程的时候是借助了欧几里得,所以窝们这个式子递归的时候也需要改变a,b。让a1,b1变成b,a % b;
        y -= (a / b) * x;//这里再来处理y转移的时候后面的那一部分。直接在递归的过程中去减去就行了,由于减完后这一层就直接结束了,所以不会影响其他 % 运算……运算的结果。
    }
    

    这里再来解释一下为什么 (b == 0) 的时候,原方程必有根。

    如果 (b == 0) :

    那么原式就可以化成这个样子:

    [a * x + 0 * y = gcd(a, 0) = a ]

    那么这个式子中,如果 (x == 1) 肯定会有 :

    [x + 0 = x 原方程成立 ]

    此时, (y) 可以取任意值,所以在那个里面的 (y) 不一定要赋值为 (0)(1), (2), (3)都可以,不过赋值为 (0) 是最小的。

    既然已经知道了(b == 0) 的时候必然有解,又可以理解前面的方程转化的过程,那么恭喜你,你证完扩展欧几里得辣!!!

    你太巨辣!!!

  • 相关阅读:
    CMD指令
    六种Socket I/O模型幽默讲解
    性格与职业的选择
    为什么主引导记录的内存地址是0x7C00?
    pandas数据分析第二天
    pandas数据结构和介绍第一天
    tornado options
    tornado.web.StaticFileHandler
    mysql多条更新
    pandas
  • 原文地址:https://www.cnblogs.com/Flash-plus/p/12054975.html
Copyright © 2011-2022 走看看