发现很多以前学过的都没有整理。。
扩展欧几里得算法用于求解二元一次不定式的通解,因而被广泛使用。
设定一常数为gcd=(A,B)
令AX0+BY0=gcd(A,B)(1),
如果完成欧几里得的算法后,发现:当B=0时,gcd(A,B)=A。要满足(1)式,显然x=1,y=0。此时,把递推过程完成,得到了一组结果。但是要求得出AX+BY=gcd(A,B)这种式子的满足的根,这样还不够,因为此时的A,B不是我们输入的A,B了,这时就要利用递归过程来实现。要找到上层递归与下层递归之间的关系,通过递归的方式使A,B回到最初的值,那个时候的等式得出的X,Y才是我们需要的。
设X,Y为当前嵌套中的值,X1,Y1为之前嵌套中的值。
就有等式AX+BY=gcd(A,B)=gcd(B,A%B)=BX1+(A-(A/B)B)Y1。(A-(A/B)B=A%B)。
整理式子得AX+BY=AY1+B(X1-(A/B)Y1)
这时,我们得出了关系式:X=Y1,Y=X1-(A/B)Y1。
模板如下:
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
ll r=exgcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-(a/b)*y;
return r;
}
返回值r是最大公约数,顺带着求出了x和y的值。
得出AX+BY=C的解,还有一些步骤
(1)要AX+BY=C有整数解,必须要满足C%gcd(A,B)=0,也就是C必须是gcd(A,B)的整数倍,X,Y才能乘以相应倍数,得到正确的解。
加一行代码判断是否有整数解:
if(c%exgcd(a,b))
puts("sorry");
else
cout<<x<<" "<<y<<endl;
(2)将x=x(c/gcd(a,b)),y=y(c/gcd(a,b)),求出一组特殊解,就是平时默认的那种最小解。
x=x*(c/exgcd(a,b));
y=y*(c/exgcd(a,b));//X,Y乘以相应的倍数得到特解。
(3)这样还不能求多解,只能求出一组特殊解,再加入x=x+b,y=y-a。因为AX+BY=AX+AB+BY-AB
整理得AX+BY=A(X+B)+B(Y-A),推出X=X+B,Y=Y-A。
x=x+b;
y=y-a;
来一道题:
求方程 Ax + By + C = 0的一组解,默认就是特解了。
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
ll r=exgcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-(a/b)*y;
return r;
}
int main(){
ios::sync_with_stdio(false);
ll a,b,c;
while(cin>>a>>b>>c)
{
ll x,y;
ll gcd=exgcd(a,b,x,y);
if(c%gcd!=0)
puts("-1");
else
{
ll k=-1*c/gcd;
x*=k;
y*=k;
cout<<x<<" "<<y<<endl;
}
}
return 0;
}
再来一个得出多组解的版本:
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
ll r=exgcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-(a/b)*y;
return r;
}
int main(){
ios::sync_with_stdio(false);
ll a,b,c;
while(cin>>a>>b>>c)
{
ll x,y;
ll gcd=exgcd(a,b,x,y);
int sum=10;//要得到多少组解
if(c%gcd!=0)
puts("-1");
else
{
ll k=-1*c/gcd;
x*=k;
y*=k;
while(sum--)
{
cout<<x<<" "<<y<<endl;
x+=b;
y-=a;
}
}
}
return 0;
}