1. 程式人生 > >POJ 1061 擴充套件歐幾里得演算法解不定方程

POJ 1061 擴充套件歐幾里得演算法解不定方程

貼一個題目地址吧:http://poj.org/problem?id=1061

(下文對擴充套件歐幾里得演算法的論述基本取決於所打的程式碼模板,故不準確)

抽象題意。設青蛙跳過的圈數為K,青蛙跳的次數為T。

根據題意有X+MT ≡ Y+NT(mod L)==> LK+(N-M)*T=X-Y

那麼問題就變成求解上述方程的最小非負整數T解。

方程中N-M和X-Y可能為負,K與T為方程的不定引數,故LK+(N-M)*T可以表示L,N-M的線性組合。

那麼可以應用擴充套件歐幾里得演算法求出 LK + (N-M)*T = O的一組解(K0,T0)和O。

這裡O比較特殊,O的絕對值和L,N-M的線性組合的絕對值的最小值相等,其實也就是L,M-N的最大公約數的絕對值,這是由擴充套件歐幾里得演算法的特性決定的。

故L,N-M的所有線性組合都可以用O乘以任意整數表示,也就是O是L,M-N的任意線性組合的因子。

容易得出如果X-Y不能被O整除,那麼方程LK + (N-M)*T = X-Y無解,輸出impossible。

將上面的方程乘以V=((X-Y)/O)得到LK+(N-M)*T=X-Y的一組特解(K1=K0*V, T1=T0*V),但題目要求T為最小非負整數。

注意O為L,M-N的最大公約數,設得通解K=K1+(N-M)/O*U,T=T1+L/O*U。其中U為任意整數,代入原方程可行。

故得到T的通解,最後求通解中T的最小非負值即可。

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;

inline ll ABS(ll a) { return a>0?a:-a; }

ll extgcd(ll a,ll b,ll &x,ll &y)
{
    ll d=a;
    if(b!=0)
    {
        d=extgcd(b,a%b,y,x);
        y-=(a/b)*x;
    }
    else {x=1; y=0;}
    return d;
}

int main()
{
    ll x,y,m,n,L;
    while(~scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L))
    {
        ll t,k,c=x-y;
        ll d=extgcd(L,n-m,k,t);
        if(c%d!=0)
        {
            printf("Impossible\n");
            continue;
        }
        ll v=c/d;
        k*=v,t*=v;
        ll ppp=ABS(L/d);

        if(t<0)
        {
            while(t<0) t+=ppp;
        }
        else if(t>0)
        {
            while(t-ppp>0) t-=ppp;
        }

        printf("%lld\n",t);;
    }
}

形如p * a+q * b = c的方程

p1,q1為已知特解。

有p = p1 + b/Gcd(a, b) * t

   q = q1 - a/Gcd(a, b) * t(其中t為任意整數)     p 、q就是p * a+q * b = c的所有整數解。