关于扩展欧几里得算法

欧几里得算法:

用来求最小公倍数的一个简单的递归函数。

扩展欧几里得算法:

用来求ax+by = gcd(a,b)(为什么是gcd(a,b),我们后面会讲)这个式子中x和y的一对整数解(不是唯一,还有其他的xy解)。例如:6x+15y=3,这里的3恰好是gcd(6,15),所以算出来的x,y解就是这个式子的一个合理解。

但是只求一组解有时远远不够,而且为了省时间,不妨将每个合理解之间的关系找出来,下面开始寻找规律:我们先算出一对合理解(x1,y1),我们再设另一对(x2,y2),那么可以得到ax1 + by1 = ax2 + by2,变形得a(x1 - x2) = b(y2 - y1),因为a和b存在最小公倍数,所以我们同除gcd(a,b),得到两个互素的a'和b',那么(x1 - x2)也就必然为b'的k倍(因为a和b已经不会有任何倍数关系了),继续求可得到(y2 - y1) = ka'。那么这个式子的所有合理解就可以写成(x1-kb' , y1+ka')。

有了上面的xy解的关系,我们再来讨论c不同的情况,比如:6x + 15y = 9 和6x + 15y = 8。针对这两个情况,我们只需要判断式子中的c和gcd(a,b)的关系就ok了。如果c%gcd==0,则式子有解,且x和y的实际值和通过ax+by = gcd(a,b)求出来的x y值相差c/gcd倍;如果c%gcd != 0,则式子无解。(所以我们之前用的是ax+by = gcd(a,b),而不是其他的方程式。)

不全经过多次修改的代码:

#include <iostream>
#include <cstdio>
using namespace std;
int exgcd(int a, int b, int&x, int&y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;//这里的a其实就是最小公倍数,这里return就是相当于把欧几里得算法揉进去。
    }
    else
    {
        int r = exgcd(b,a%b,x,y);
        int t = x;
        x = y;
        y = t- a/b*y;
        return r;
    }
}
int main()
{
    //ax + by = c
    int a,b,c;
    while(cin>>a>>b>>c)
    {
        bool flag = false;
        int x,y;
        int gcd = exgcd(a,b,x,y);
        if(c%gcd != 0)
        {
            cout << "无解" << endl;
        }
        else
        {
            int k = c/gcd;
            x*=k,y*=k;    //得到了满足方程的一组解
            //下面是把x和y都变成正数,不是必须的
            /*k = 1;
            int ax = a/gcd;
            int bx = b/gcd;
            while(x-k*bx <=0 || y+k*ax <= 0)
            {
                k++;
            }
            x = x-k*bx;
            y = y+k*ax;*/
            printf("%d*%d + %d*%d = %d\n", a,x,b,y,c);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wangjunchengno2/article/details/79645128