【数论】欧几里得算法
一、具体内容:
内容很简单,只有一个式子:gcd(a,b)=gcd(b,a%b),可以用来求a与b的最大公因数
二、不严谨的证明:
首先不妨设a>b,r=a%b且r≠0,得到a=kb+r(a,b,r,k均为正整数)
设d是a和b的一个公因数,即d|a,d|b
已知r=a-kb,将两边同除d,即r/d=a/d-kb/d,a,b均是d的倍数,
因此a/d与kb/d均为整数,可得r/d为整数,即d|(a%b)
因此d也是b,a mod b的公约数,因(a,b)与(b,a%b)的公因数相等,
所以gcd(a,b)=gcd(b,a%b),得证
三、代码实现
我们很容易就可以看出gcd(a,b)的子问题结构,接下来考虑边界,当a%b==0,即a时b的倍数时,显而易见gcd(a,b)=b
#include<bits/stdc++.h> using namespace std; int x,y; int GCD(int a,int b) { if(!(a%b)) return b; return GCD(b,a%b); } //可以用"?"运算符将函数压缩成这样 //int GCD(int a,int b){return a%b?GCD(b,a%b):b;} int main() { scanf("%d%d",&x,&y); printf("%d",GCD(x,y)); }
四、算法优化
上述算法的时间已经相当优秀了,我们只能用位运算对常数进行优化
#include<bits/stdc++.h> using namespace std; int x,y; int GCD(int a,int b) { if(a==b) return a; if((a&1)&&(b&1)) return gcd(b,abs(a-b)); else if((a&1)&&(!(b&1))) return gcd(a,b>>1); else if((!(a&1))&&(b&1)) return gcd(a>>1,b); else return gcd(a>>1,b>>1)<<1; } int main() { scanf("%d%d",&x,&y); printf("%d",GCD(x,y)); }