欧几里德 及 扩展欧几里德
昨晚看了一点点的数论,是一个直线上的点的例题,正好用到了欧几里德算法。于是就网搜了一下,做一些笔记,以后好留着自己看。
欧几里德算法其实就是求两个整数的最大公约数的算法,gcd函数应该都知道,gcd(a,b)就是求a,b的最大公约数。根据最大公约数的性质:gcd(a,b) = gcd(b,a) = gcd(b,a%b);
也就是我们熟悉的辗转相除法,辗转相除的代码
//非递归实现 int gcd(int a,int b) { if(a < b) swap(a,b); while(b) { int temp = b; b = a % b; a = t; } return a; } //递归实现 int gcd(int a,int b) { if(a < b) swap(a,b); if(b) gcd(b, a % b); return a; }
扩展欧几里德算法
扩展欧几里德是:对于不全为零的 a , b来说,必然存在整数对 x , y,使得 gcd( a, b) = a * x + b * y 成立。下面是讲如何求解 x , y 。
设 a>b。
1. 显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2. ab < > 0 时
设 a * x1 + b * y1 = gcd(a,b);
b * x2 + (a mod b) * y2 = gcd(b,a mod b);
根据欧几里德原理有: gcd(a,b)=gcd(b,a mod b);
则:a * x1 + b * y1 = b * x2 + (a mod b) * y2;
即:a * x1 + b * y1 = b * x2 + (a - ( a / b ) * b ) * y2 = ay * 2 + b * x2 - ( a / b ) * b * y2;
根据恒等定理得:x1 = y2; y1 =x2 - ( a / b) * y2;
代码实现
int exgcd(int a,int b,int &x,int &y) { if(b == 0) { x = 1; y = 0; return a; } int d = exgcd(b, a % b,x,y); int temp = x; x = y; y = temp - a / b * y; return d; }
欧几里德的一个应用就是求解 线性方程 a * x + b * y + c = 0;的解。
有上可知方程式 gcd(a , b) = a * x + b * y;可以求出一对整数对 x y 满足该方程,设 d = gcd( a ,b);
则对于方程gcd(a , b) = a * x + b * y 变为:d = a * x + b * y , 方程两边同时除以 d 的 1 = a * ( x / d) + b * ( y / d) ,再同时乘以 c 得 c = a * ( c * x / d ) + b * ( c * y / d) ;所以对于方程 c = a * x + b * y ; 来说,他第一组解即为:
x1 = c * x / d, y1 = c * y / d (其中 x 和 y是gcd( a,b) = a * x + b * y , 的一组整数解,d 为gcd(a,b)),
所以对于方程式 c = a * x + b * y 的任意一组解即为 n ,m 则
n = x1 + b * gcd(a,b) * t; m = y1 - a * gcd(a,b) * t; t 为任意正整数。
如果 c % gcd(a,b) != 0 则 方程 c = a * x + b * y 无解。
例题 pku 1061 http://poj.org/problem?id=1061
根据题意 设 step 青蛙跳的步数
则有 abs((x + m × t) - (y + n × t)) = k × L ; 成立
则有 (m - n) × t - (y - x ) = k × L;
则有 (m - n ) × t - k × L = (y - x)
所以 令 temp = (m - n),kemp = (y - x),cemp = L;
则原式变为 temp * t + cemp * k = kemp;
即为 a * x + b * y = c;的形式
参见代码
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 using namespace std; 5 typedef long long ll; 6 ll temp,kemp; 7 int exgcd(int a,int b) 8 { 9 if(b == 0) 10 { 11 temp = 1; 12 kemp = 0; 13 return a; 14 } 15 ll ans = exgcd(b,a % b); 16 ll t = temp; 17 temp = kemp; 18 kemp = t - a / b * temp; 19 return ans; 20 } 21 int main() 22 { 23 ll x,y,m,n,L; 24 while(cin>>x>>y>>m>>n>>L) 25 { 26 if(m == n && x != y) 27 { 28 cout<<"Impossible\n"; 29 continue; 30 } 31 ll a = m - n; 32 ll b = L; 33 ll c = y - x; 34 if(a < 0) 35 { 36 a = -a; 37 c = -c; 38 } 39 ll d = exgcd(a,b); 40 if(m == n || c % d != 0) 41 { 42 cout<<"Impossible\n"; 43 } 44 else 45 { 46 b /= d; 47 c /= d; 48 ll t = c * temp; 49 cout<<(t % b + b) % b<<endl; 50 } 51 } 52 return 0; 53 }