详解扩展欧几里得算法

详解扩展欧几里得算法:

引入:

1.求不定方程的通解:

在这里插入图片描述

2.欧几里得定理:(可以参考:链接

在这里插入图片描述

3.裴蜀定理:

在这里插入图片描述

4.问题来了:如何求出方程ax+by=gcd(a,b)的一个特解呢?

其中gcd(a,b)为a, b的最大公约数,我们假设为 d ;
先看这段代码(求a, b的最大公约数)

def gcd(a, b):
    if b==0:          # 终止条件
        return a
    return gcd(b, a%b)      # return 直到将最终结果 a 带出去
def main():
    a = gcd(8251, 6105)     # a 就是最大公约数
    print(a)
main()

接着想:递归到最后一层时, 该层的 a =gcd(a,b),b=0;所以对于此时的方程:ax+by = gcd(a,b)
有一个特解(1,0);
注意:此时的方程是当前层的方程,他和咱们要求的第一层的方程并不同(是指a,b不同;但是gcd(a,b)是相同的;因为gcd(a,b)=gcd(b,a%b))

那么问题又来了:如何根据最后一层推导出上一层,让其迭代出来呢?

敲黑板:(注意在递归算法中,永远都是先得到下面一个状态的值)
假设 当前层 的状态为 ax+by = gcd(a,b) ; 那么根据 代码 执行到 下一层 时的状态是什么呢?
——————————————————————————————————————
没错:b*x + (a%b)*y = gcd(b, a%b)

又知道:a%b = (a - (a/b) b) 其中a/b为向下取整
在这里插入图片描述
那么 b
x + (a%b)y = gcd(b, a%b) 可以化简为:ay + b*(x - (a/b)*y) = gcd(b, a%b)
假设这一层的特解为( y, x - (a/b)*y )
我们知道这一层的 解 是从上一层(即:当前层)得来的;
——————————————————————————————————————
所以当前层的 解(x, y)应该根据( y, x - (a/b)*y ) 来转换状态
所以:对上面的代码增加相应状态转换的代码:

x = 0    # 这里将x, y定义为全局变量:因为每一层操作的都是同一个x, y
y = 0    # 而 a,b 对于每一层来说是独立的
def exgcd(a, b):
    global x, y
    if b==0:
        x = 1
        y = 0
        return a
    d = exgcd(b, a%b)
    tmp = y            # 下面三行代码即为 “状态转换”
    y = x-int(a/b)*y
    x = tmp
    return d    # d 为最大公约数; 逐层return 回归出去,回归到 d = exgcd(b, a%b) 这里;最终return
                # 回归到main函数
    #(递归就是 递推+回归)

5.下面找个题练一练:

动手练一练(代码稍后给出)

6.那么还有一个问题:如果让求ax+by = c 的一个特解,如何求呢?

显然要分类讨论:

1.如果 c 不是gcd(a, b)的整数倍,自然不存在解(裴蜀定理)

2.如果 c 是gcd(a, b)的整数倍:
请看下图:
在这里插入图片描述

7.最后一个问题:

我们知道 特解(x, y)有可能出现负数;如何得到最小正整数解呢?

对得到的x进行:

x = ( x % b + b ) % b;(求出的就是最小正整数解)

然后根据 方程 ax+by = c 求得 y 值

8.找个提练一练:

1.练一练吧!!!!!!嘻嘻!!代码稍后给出!
2.对于负数的处理

# 第一题  (不知为何,这一题在这个平台AC不了,c++可以AC)
x = 0
y = 0
def exgcd(a, b):
    global x, y
    if b==0:
        x = 1
        y = 0
        return a
    d = exgcd(b, a%b)
    tmp = y
    y = x-int(a/b)*y
    x = tmp
    return d

    pass
def main():
    global x, y
    row = eval(input())
    for i in range(row):
        line = input().split(" ")
        a, b, m= eval(line[0]), eval(line[1]), line[2]
        d = exgcd(a, b)
        if b%d!=0:
            print("impossible")
            continue
        x *= int(b/d)
        print(x)
    return
main()
# 第二题  已经AC
x = 0
y = 0
def exgcd(a, b):
    global x, y
    if b==0:
        x = 1
        y = 0
        return a
    d = exgcd(b, a%b)
    tmp = y
    y = x-int(a/b)*y
    x = tmp
    return d


def main():
    global x, y
    line = input().split(" ")
    a = eval(line[0])
    b = eval(line[1])
    c = eval(line[2])
    k = eval(line[3])

    for i in range(int(k/c)):
        d = exgcd(a, b)
        num = k - c*i
        if (num % d)!=0:
            continue
        x = x*(num/d)
        y = y*(num/d)
        z = i
        x = (x%b+b)%b
        y = (num-a*x)/b
        if x>=0 and y>=0:
            print("{} {} {}".format(int(x), int(y), i))
            break
        else:
            return
        #return

main()

9.结束

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值