第一章
欧几里德算法又称辗转相除法,用于计算两个整数a, b的最大公约数。
基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd(b,r),即gcd(a,b)=gcd(b,a%b)
证明:
(1)假设d是a,b的一个公约数,a可以表示成a = kb + r,则r = a % b,
则有d|a, d|b, 而r = a – kb,故 d|r,
因此d是(b,a mod b)的公约数;
(2)假设d 是(b,a mod b)的公约数,
则 d | b , d | r ,而 a = kb +r
因此, d也是(a,b)的公约数
因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证
计算gcd(m, n)的欧几里得算法:
(1)如果n=0,返回m的值作为结果, 同时过程结束; 否则, 进入第二步.
(2)取m%n的余数, 将余数赋给r;
(3)将n的值赋给m, 将r的值赋给n, 返回第一步。
分析:
通过观察,我们发现,每经过一次循环,参加运算的两个算子中的后一个都会变得更小,而且绝对不会变成负数。
#include <iostream>
using namespace std;
unsigned int euclid(unsigned int m, unsigned int n)
{
unsigned int r = 0;
while (0 != n)
{
r = m % n;
m = n;
n = r;
}
return m;
}
int main()
{
cout << euclid(12, 60) << endl;
return 0;
}
扩展欧几里德算法
对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,
必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。
(1)当b=0时, 有gcd(a,b)=a, 此时x=1, y=0
(2)当b不为0时, 根据欧几里得定理gcd(a,b)=gcd(b,a%b)
可得ax+by=gcd(a,b)
gcd(b,a%b)=bx′+(a%b)y′,即
ax+by=bx′+(a%b)y′=bx′+(a−b*[a/b])y′
移项得
ax+by=bx′+(a%b)y′=ay′+b(x′−[a/b]y′)
根据恒等定理,有
x=y′
y=x′−[a/b]y′
注释:[a/b]代表取小于a/b的最大整数
补充:关于使用扩展欧几里德算法解决不定方程的办法
对于不定整数方程pa+qb=c, 若 c % gcd(p, q)=0,则该方程存在整数解,否则不存在整数解。
上面已经列出找一个整数解的方法,在找到p * a+q * b = gcd(p, q)的一组解p0,q0后,p * a+q * b = gcd(p, q)的其他整数解满足:
p = p0 + b/gcd(p, q) * t
q = q0 – a/gcd(p, q) * t(其中t为任意整数)
至于pa+qb=c的整数解,只需将p * a+q * b = gcd(p, q)的每个解乘上 c/gcd(p, q) 即可。
http://poj.org/problem?id=1061
由题意可得:
x+mt≡y+nt(modL)
–>
(m−n)t≡y−x(modL)
–>
(m−n)t+Lk=y−x
然后,用exeuclid求
(m−n)t+Lk=gcd(m−n,L)
设r=gcd(m-n,L),c=y-x。
若c%r!=0,则无解。
这样解出t0后,最终答案就是:
(t0*c/r)%(L/r)
关于这个结论的证明:
ax1+by1=c
而我们已经解得
ax+by=gcd(a,b)=d
此时将第二个方程左右同时乘c/d,则可得:
ax*c/d+by*c/d=c
所以: x1=x0*c/d
这样并没有完,因为这只是一组解,我们要求最小正整数解。
我们知道:若一组 < x,y > 是ax+by=c的一组解,那么
<x−b/d,y+a/d>
也是原方程的一组解。
这样我们只需要让解得的x不断减b/d,直到再减就为负数时,所得的x就是我们要的解。
其实这个过程就是模运算,所以最小正整数解就是:
x1=(x0*c/d)mod b/d
#include <iostream>
#include <stdlib.h>
using namespace std;
long long exeuclid(long long a, long long b, long long &x, long long &y)
{
if (0 == b)
{
x = 1;
y = 0;
return a;
}
long long r = exeuclid(b, a%b, x, y);
long long tmp = x;
x = y;
y = tmp – (a/b) * y;
return r;
}
int main()
{
long long x, y, m, n, L, r, t1, t2, x0, y0, res;
cin >> x >> y >> m >> n >> L;
t1 = m > n ? (m – n) : (n – m);
if (m < n)
{
res = x;
x = y;
y = res;
}
t2 = y > x ? (y – x) : (x – y);
r = exeuclid(t1, L, x0, y0);
if (t2%r != 0 )
cout << “Impossible” << endl;
else
{
t1 = L/r;
res = ((x0*(y-x)/r)%t1+t1)%t1;
cout << abs(res) << endl;
}
return 0;
}