(一)欧几里得算法又称辗转相除法,是求解两个数的最大公约数的算法,基本定义为:
设 a=qb+r,其中a,b,q,r都是整数,则:gcd(a,b)= gcd(b,r)
利用递归实现该算法:
long long gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); }
辗转相除法的应用:(水题)
nefu 116:两仪剑法 http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=116
题目分析:
由题意知:该题是要求M和N的最小公倍数,由于数据较大,正常用会导致数据溢出而WA,所以要利用该求最小公倍数的公式变形,先去除,再去乘,来进行数据范围的控制,公式为:
则代码实现如下:
#include <iostream> #include <cstdio> using namespace std; long long gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); } int main() { int m,n; while(scanf("%d%d",&m,&n)!=EOF) { printf("%lld\n",(m/gcd(m,n))*n); } return 0; }
设a和b不全为0,则存在整数x和y,使得 gcd(a,b)= xa + yb
拉梅定理:用欧几里得算法计算两个正整数的最大公因子时,所需的除法次数不会超过两个整数中较小的那个十进制数的倍数的5倍。
拉梅定理推论:求两个正整数a,b,a>b 的最大公因子需要O(log2a)3次的位运算。
由扩展欧几里得的推论:如果gcd(a,b)=1,则称a与b互素。
整数a和b互素的充分必要条件:存在整数x和y,使得xa+yb=1 。
扩展欧几里得算法实现:
typedef long long int64; using namespace std; int64 exgcd(int64 m,int64 & x,int64 n,int64 & y) //Extend Euclid { int64 x1,y1,x0,y0; x0 = 1;y0 = 0; x1 = 0;y1 = 1; int64 r=(m%n+n)%n; int64 q=(m-r)/n; x=0;y=1; while(r) { x=x0-q*x1; y=y0-q*y1; x0=x1; y0=y1; x1=x; y1=y; m=n; n=r; r=m%n; q=(m-r)/n; } return n; //返回值为m和n的最大公约数,修改后的x和y的值是所求值 }扩展欧几里得算法应用:
POJ 1061:青蛙的约会 http://poj.org/problem?id=1061
题目分析:设两只青蛙跳了t步后相遇,A蛙的坐标为:x+mt ,B蛙的坐标为:y+nt 。两蛙相遇的条件为: ,公式变形为:
设
,求满足
的最小t(t>0),即求一次同余方程
的最小正整数解。具体求解过程为3步:
(1)写出方程,用扩展欧几里得函数求解,即
此时X是一个解,但不是最后的解。
(2)若(x-y)%gcd(n-m,L)==0, 则有解(指x和y都有解)。
(3)有解后,设M=gcd(n-m,L),X=X(x-y)/M
然后:(X%(L/M)+(L/M))%(L/M) 就是最后的解,即为本题的t的值。
代码实现如下:
#include <iostream> #include <cstdlib> typedef long long int64; using namespace std; int64 exgcd(int64 m,int64 & x,int64 n,int64 & y) //Extend Euclid { int64 x1,y1,x0,y0; x0 = 1;y0 = 0; x1 = 0;y1 = 1; int64 r=(m%n+n)%n; int64 q=(m-r)/n; x=0;y=1; while(r) { x=x0-q*x1; y=y0-q*y1; x0=x1; y0=y1; x1=x; y1=y; m=n; n=r; r=m%n; q=(m-r)/n; } return n; //返回值为m和n的最大公约数,修改后的x和y的值是所求值 } int main() { int yy; int64 r,t; int64 x,y,m,n,l; int64 ar,br; cin>>x>>y>>m>>n>>l; int64 M=exgcd(n-m,ar,l,br); if((x-y)%M||m==n) cout<<"Impossible"<<endl; else { int64 s=l/M; ar=ar*((x-y)/M); ar=(ar%s+s)%s; cout<<ar<<endl; } return 0; }