欧几里得算法
欧几里得算法 (Euclidean algorithm) 是用来解决最大公约数问题的,通常采用辗转相除法。
代码:
int gcd(int a, int b)
{
return b? gcd(b, a%b): a;
}
···············································································································
拓展欧几里得算法
拓展欧几里得算法(Extended Euclidean Algorithm)是基于欧几里得算法而来解一类特殊的线性丢番图方程。
解决问题:ax+by=1(即a,b互质),求解x,y。
代码:
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;
}
对于ax+by=gcd(a,b)我们可以得到一组解x和y
但往往我们会遇到ax+by=c这样的问题,那和前面的扩展gcd又有什么关系呢?
前提条件:若c mod gcd(a, b) =0,则该方程(ax+by=c)存在整数解,否则不存在整数解
对于ax+by=gcd(a,b)求出来的一组整数解x0和y0
对应ax+by=c的一组整数解x1和y1,有x1=x0(d/gcd(a,b)),y1=y0(d/gcd(a,b))
对于全部解,有x=x0+b/gcd(a,b)t,y=y0-a/gcd(a,b)t (其中t为任意常整数)
由于x0,y0,a,b,gcd(a,b)都是已经求出的数(可以看作常数),所以对于x,y我们可以看作是自变量为t,因变量为x,y的两个一次函数,所以可以知道,这2个函数是单调的
x = x0 + b/gcd(a,b)*t;
y = y0 - a/gcd(a,b)*t;
(x0, y0 为方程的一组特解, t为整数)
证明是根据线性丢番图方程而来的。
例题:青蛙的约会
POJ - 1061
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long int
ll gcd(ll a, ll b)
{
return b? gcd(b, a%b): a;
}
void exgcd(ll a, ll b, ll &x, ll &y)
{
if(b==0)
{
x=1;
y=0;
return ;
}
exgcd(b, a%b, x, y);
ll t=x;
x=y;
y=t-(a/b)*y;
return ;
}
int main()
{
ll x, y, m, n, L;
ll T, P, d;
ll a, b, c;
while(~scanf("%lld%lld%lld%lld%lld", &x, &y, &m, &n, &L))
{
a=n-m;
b=L;
c=x-y;
d=gcd(a, b);
if(c%d) printf("Impossible\n");
else
{
int r=d;
a/=d;
b/=d;
c/=d;
exgcd(a, b, T, P);
T=T*c;
T=(T%b+b)%b;
printf("%lld\n", T);
}
}
return 0;
}
例题:The Balance
POJ - 2142
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long int
ll gcd(ll a, ll b)
{
return b? gcd(b, a%b): a;
}
void exgcd(ll a, ll b, ll &x, ll &y)
{
if(b==0)
{
x=1;
y=0;
return ;
}
exgcd(b, a%b, x, y);
ll t=x;
x=y;
y=t-(a/b)*y;
return ;
}
int main()
{
ll a, b, c, x, y, vx, vy;
while(~scanf("%lld%lld%lld", &a, &b, &c)&&(a||b||c))
{
ll r=gcd(a, b);
a/=r;
b/=r;
c/=r;
exgcd(a, b, x, y);
vx=x*c;
vx=(vx%b+b)%b;
vy=abs((c-a*vx)/b);
y=y*c;
y=(y%a+a)%a;
x=abs((c-b*y)/a);
if(x+y>vx+vy)
{
x=vx;
y=vy;
}
printf("%lld %lld\n", x, y);
}
return 0;
}