Loading

扩展欧几里德算法——求最小整数解

这是一个数学推导!!!

 

首先我们已经知道了,如何通过扩展欧几里德算法,求出方程的其中一组解了

那么就可以继续往下看

  

  给出两个方程

    ax1+by1=gcd(a,b)

    ax2+by2=gcd(a,b)

  所以可以推出

    ax1+by1=ax2+by2

    a(x1-x2)=b(y2-y1)

  然后我们知道gcd(a,b)为a,b的最大公因数,所以我们将 A=a/gcd(a,b),B=b/gcd(a,b),接着往下推出

    A(x1-x2)=B(y2-y1)

  现在A和B两个已经是互素了,所以又可以接着推出

    (这个地方要好好理解,重点!)

    A*(n*B)=B*(n*A)

    (x1-x2)=n*B

    (y2-y1)=n*A

  这里我们从x入手

    (x1-x2)=n*B

    x1=x2+n*B

  由此,我们推出了x解的通解公式    x=x0+n*B

  同理,我们推出了y解的通解公式 y=y0-m*A

 

  那么我们如果要求 x 的最小整数解,也就是 x0, 就是 x0=x%B

  如果我们要求的是  ax+by=c,还得先转化  x=x*c/gcd(a,b).

  然后套入我们的公式

  B=b/gcd(a,b)

  x0=x%(b/gcd(a,b))

  嗯,到此结束,下面给下实现代码

 

#include <bits/stdc++.h>
#include<unordered_set>
//freopen("in.txt", "r", stdin);

using namespace std;
typedef double dou;
typedef long long ll;
typedef pair<ll, ll> pii;

#define M 1050
#define inf 0x3f3f3f3f
#define mod 1000000007
#define W(a) while(a)
#define lowbit(a) a&(-a)
#define left k<<1
#define right k<<1|1
#define ms(a,b) memset(a,b,sizeof(a))
#define debug(a) cout<<#a<<" == "<<a<<endl
#define false_stdio ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

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

ll solve(ll a, ll b, ll c) {
    ll x, y, z;
    z = exgcd(a, b, x, y);
    if (c%z)return -1;//不成立
    //return x; //不需要最小正整数的话直接返回x
    x *= c / z;
    b = abs(b / z);
    return (x%b + b) % b;
}

int main() {
    false_stdio;
    ll a, b, c;
    cin >> a >> b >> c;
    
    ll x = solve(a, b, c);
    ll y = (c - x * a) / b;
    
    if(x>=0)//看x大小要求而定
        cout << x << ' ' << y << endl;
        
    

    return 0;
}

 

posted @ 2019-05-11 23:49  苟住  阅读(1855)  评论(0编辑  收藏  举报