扩展欧几里得
经典问题,找出一对整数,使得ax+by=gcd(a,b)
gcd表示最小公约数,代码附上:
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
假设上述函数的一个特解(x0,y0)根据二元一次不定方程的解法可得
x=x0+b/gcd;
y=y0-a/gcd;
得到它的通解形式,所以我们只要求出它的一个特解就好了,怎么求这个特解呢?
让我们来分析一下gcd的过程最后一个状态是gcd(a,0)也就是 a1+0b=gcd;a=gcd;
由欧几里得我们知道gcd(a,b)=gcd(b,a%b);
bx0+(a%b)y0=gcd
a%b=a-(a/b)b;除法为向下取余的除法
代入得到式子 bx0+(a-(a/b)b)y0=gcd;
化简 ay0+b(x0+a/by0)=gcd
对比ax+by=gcd得到
x=y0
y=x0+a/by0;
所以得出下面代码
int exgcd(int a,int b,int &x,int &y)
{
if(!b){x=1;y=0;return a;}
int g=exgcd(b,a%b,x,y);
int cnt=x;
x=y;
y=cnt-a/b*y;
return g;
}
这是一道简单例题,不过有了最小整数的条件,可以去尝试尝试https://vjudge.net/problem/HDU-2669
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include<set>
using namespace std;
#define fin(a,n) for(int i=a;i<=n;i++)
#define fjn(a,n) for(int j=a;j<=n;j++)
#define fkn(a,n) for(int k=a;k<=n;k++)
#define ll long long int
#define maxn 20000
ll exgcd(ll a,ll b,ll &x,ll &y)//扩展欧几里得;
{
if(b==0)
{x=1;y=0;return a;}
int g=exgcd(b,a%b,x,y);
int cnt=y;
y=x-(a/b)*y;
x=cnt;
return g;
}
ll gcd(ll a,ll b)//普通欧几里得
{
return b?gcd(b,a%b):a;
}
int main()
{
ll a,b,x,y;
while(scanf("%lld %lld",&a,&b)!=EOF)
{
if(gcd(a,b)==1)
{
exgcd(a,b,x,y);
x%=b;//此处为该题多的地方,x可为正负,若为正,直接对b取余,
//若为负,取余后再+上相应的b变成正数就好,具体请自学负数的取余
while(x<0)x+=b;
y=(1-a*x)/b;
printf("%lld %lld\n",x,y);
}
else printf("sorry\n");
}
}