1. 程式人生 > >gcd歐幾里德演算法/extgcd擴充套件歐幾里德演算法以及在解不定方程中的應用

gcd歐幾里德演算法/extgcd擴充套件歐幾里德演算法以及在解不定方程中的應用

這個應該是我在noip前就應該會的東西 ,但是當時也許只是記下了程式碼吧 ,現在有諸多的不理解。後來藉著書和幾篇部落格弄懂了並小證了一下,鑑於網上有些部落格關於這個的寫的真的不好看,所以自己來總結一下,順帶以後也能看。
順帶一提,gcd(a,b)表示a,b的最大公約數。

歐幾里德演算法

輾轉相除法求最大公約數問題,同可求最小公倍數。
既然是輾轉相除法,自然就是%%%,%到互相整除為止。程式碼也很詳盡簡潔。

int regulargcd(int x,int y)
{
    return y==0?x:(regulargcd(y,x%y));
}

最小公倍數為兩數之積除以他們的最大公約數,相信大家都能明白。

擴充套件歐幾里德演算法

我之前一直困惑的是它為什麼可以求不定方程的解,後來基本明白了:
給定一個形如方程ax+by=d,求它的整數解。
我們知道a,b為整數,d是整數,使得x,y為整數解,那麼需要約掉係數中相同的部分,於是

ax+by=dgcd(a,b)|d
所以說,假設我們有d=gcd(a,b)t,則方程ax+by=d的解為agcd(a,b)x+bgcd(a.b)y=gcd(a,b)的t倍,那麼原問題轉化為求方程agcd(a,b)x+bgcd(a.b)y=gcd(a,b)的解了。

再推到一般,若a,b互質,有ax+by=1有解。

然後接下來我們考慮特殊解的情況:

gcd(a,b)遞迴的最終結果為gcd(k,0),假定方程有解,那麼最終有a1+b0=gcd(a,b),即a1+b0=1,即x=1y=0出現,這是在求gcd時遞迴形成的。若我們也這樣地求解方程呢?

於是我們來找ax+by=gcd(a,b)bx+(a%b)y=gcd(b,a%b)的關係,由於a%b=a(a/b)b(整數除法) 所以代入有

ay+b(xa/by)=gcd(a,b)=gcd(b,a%b)

於是原方程解為x=y,y=x(a/b)y
這樣我們就能遞迴地計算方程的解了。

int extgcd(int a,int b,int &x,int &y
) { if(b==0) { x=1; y=0; return a; } else { int ans; ans=extgcd(b,a%b,x,y); int tmp=x; x=y; y=tmp-(a/b)*y; return ans; } }

不定方程不是有很多解嗎?是的,這只是最小解。設最小解為x0,y0,它的所有解為x=x0+bgcd(a,b)y=y0+agcd(a,b)。(自己帶到方程裡展開就有恆等式,這裡不證了)當gcd(a,b)=1時,有x=x0+b,y=y0+a

    while(x<=0)
    {
        x+=(b/res);
    }
    printf("%d\n",x);
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
//zoj3609 AC
using namespace std;

int extgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    else
    {
        int ans;
        ans=extgcd(b,a%b,x,y);
        int tmp=x;
        x=y;
        y=tmp-(a/b)*y;
        return ans;
    }
}

int regulargcd(int x,int y)
{
    return y==0?x:(regulargcd(y,x%y));
}

int main()
{
    int a,b;
    int cas;
    scanf("%d",&cas);
    for(int z=0;z<cas;z++)
    {
        scanf("%d%d",&a,&b);
        int x,y;
        if(regulargcd(a,b)==1)
        {
            int res=extgcd(a,b,x,y);
            if(x>0)
            {
                printf("%d\n",x);
            }
            else
            {
                while(x<=0)
                {
                    x+=(b/res);
                }
                printf("%d\n",x);
            }
        }
        else
        {
            printf("Not Exist\n");