还是要心平气和地对待数论(
0、欧几里得算法
即辗转相除法,可以求出两整数a,b的最大公约数(和最小公倍数),用gcd(a,b)表示.
递归实现如下:
1 | int gcd(int a,int b){ |
gcd(a,b)具有以下性质:
gcd(a,b)=gcd(b,a)=gcd(-a,b)=gcd(abs(a),abs(b))
gcd(a,b)=gcd(b,a%b)
1、扩展欧几里得
扩展欧几里得即欧几里得算法的扩展:
gcd(a,0)=a
以及由此引申出的对二元一次不定方程整数解的求解算法.
求解:ax+by=gcd(a,b),(x,y∈Z)
(其中,有定理ax+by=gcd(a,b)解一定存在,且ax+by=c有解的充要条件为c=k*gcd(a,b),k∈Z)
设 a>b 当 b=0 时,gcd(a,b)=a,x=1,y=0;
a>b>0时 设
ax1+by1=gcd(a,b)……①
bx2+(a%b)y2=gcd(b,a%b)……②
由性质, ∵gcd(a,b)=gcd(b,a%b)
∴ax1+by1=bx2+(a%b)y2
=>ax1+by1=ay2+b(x2-[a/b]*y2)
由此,可以递归得到原方程的一组解:
{
x1=y2
y1=x2-[a/b]*y2
}
其中x1,y1由x2,y2得到,由b=0时的边界条件,即可回溯求解.
其代码实现如下:
1 | int extend_euclid(int a,int b,int *x,int *y){ |
可以看到,扩展欧几里得的写法包涵了欧几里得算法的内容,即返回值为gcd(a,b),同时,调用后实参x,y的值即为方程ax+by=gcd(a,b)的一组解.
当不需要返回gcd(a,b)时,形式还可以为:
1 | void extend_euclid(int a,int b,int *x,int *y){ |
2.不定方程的通解
在得到方程ax+by=gcd(a,b)的一组解x0,y0后,
方程ax+by=c(c mod gcd(a,b)=0)的一组解为:
x1=x0*(c/gcd(a,b)),
y1=y0*(c/gcd(a,b))
由此,不定方程ax+by=c的通解为:
x=x1+b/gcd(a,b)*k,
y=y1-a/gcd(a,b)*k(k∈Z)
以上即扩展欧几里得的内容,应用可参见:
青蛙的约会