您的位置:首页 > 其它

扩展欧几里得算法模板(希望永远不要搞懂了)

2016-08-05 18:40 281 查看


扩展欧几里得

上述谈到的最大公约数算法是数学家欧几里德提出的,同时,他也提出了扩展欧几里德算法来解决整数二元一次不定方程问题。


整数二元一次不定方程

形如a*x+b*y=c(a,b均不为0)的方程,a,b,c都是整数,求(x,y)的整数解。


1 判断是否有解

整数二元一次不定方程有解的充分必要是gcd(a,b)|c。如果不能整除则无解。


2 扩展欧几里德求特解

欧几里德给出了计算a*x+b*y=gcd(a,b)的解法

long long exgcd(long long a,long long b,long long &x,long long &y)

{

if (b==0) { x=1,y=0; return a; }

long long d=exgcd(b,a%b,x,y);

long long tmp=x;

x=y;

y=tmp-a/b*y;

return d;

}



3 通解

a*x+b*y=gcd(a,b)在有解并求出特解(x,y)的情况下,通解可以表示为 

对于一般式a*x+b*y=c,如果有解,只需把a*x+b*y=c的特解乘上c/gcd(a,b)即可得到其特解,通解还是一样的公式。


4 例子

求出特解和一个通解

int main(int argc, char* argv[])

{

long long a,b,c;

scanf("%lld%lld%lld",&a,&b,&c);

long long x,y,d;

d=exgcd(a,b,x,y);

if (c%d!=0) printf("No solution!\n");

else

{

a/=d,b/=d,c/=d;

x*=c,y*=c;

printf("特解: %lld %lld\n",x,y);

printf("一个通解: %lld %lld\n",x+b,y-a);

}

return 0;

}


请思考一下,如何求出不定方程的正整数解个数。

 依然很简短,相比欧几里德算法,只是多加了几个语句而已。

    这就是理论部分,欧几里德算法部分我们好像只能用来求解最大公约数,但是扩展欧几里德算法就不同了,我们既可以求出最大公约数,还可以顺带求解出使得: a*x + b*y = gcd 的通解 x 和 y

    扩展欧几里德有什么用处呢?

    求解形如 a*x +b*y = c 的通解,但是一般没有谁会无聊到让你写出一串通解出来,都是让你在通解中选出一些特殊的解,比如一个数对于另一个数的乘法逆元

    什么叫乘法逆元?

    


    这里,我们称 x 是 a 关于 m 的乘法逆元

    这怎么求?可以等价于这样的表达式: a*x + m*y = 1

    看出什么来了吗?没错,当gcd(a , m) != 1 的时候是没有解的这也是 a*x + b*y = c 有解的充要条件: c % gcd(a , b) == 0

    接着乘法逆元讲,一般,我们能够找到无数组解满足条件,但是一般是让你求解出最小的那组解,怎么做?我们求解出来了一个特殊的解 x0 那么,我们用 x0 % m其实就得到了最小的解了。为什么?

可以这样思考:

    x 的通解不是 x0 + m*t 吗?

    那么,也就是说, a 关于 m 的逆元是一个关于 m 同余的,那么根据最小整数原理,一定存在一个最小的正整数,它是 a 关于m 的逆元,而最小的肯定是在(0 , m)之间的,而且只有一个,这就好解释了。

    可能有人注意到了,这里,我写通解的时候并不是 x0 + (m/gcd)*t ,但是想想一下就明白了,gcd = 1,所以写了跟没写是一样的,但是,由于问题的特殊性,有时候我们得到的特解 x0 是一个负数,还有的时候我们的 m 也是一个负数这怎么办?

    当 m 是负数的时候,我们取 m 的绝对值就行了,当 x0 是负数的时候,他模上 m 的结果仍然是负数(在计算机计算的结果上是这样的,虽然定义的时候不是这样的),这时候,我们仍然让 x0 对abs(m) 取模,然后结果再加上abs(m) 就行了,于是,我们不难写出下面的代码求解一个数 a 对于另一个数 m 的乘法逆元:

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: