前言
在查找题目相关资料时接触到一些新鲜东西,记录记录
网址:AT_agc001_b [AGC001B] Mysterious Light 题解
一、更相减损术
原文:
约分术曰:可半者半之;不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。
翻译
任意给定两个正整数:
1)判断它们是否都是偶数。若是,则用2约简;
2)以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数;
3)继续这个操作,直到所得的被减数和差相等为止。
4)第1步中约掉的若干个2的积与第2步中其中一个等数的乘积就是所求的最大公约数
原理:
刘徽:其所以相减者,皆等数之重叠,故以等数约之。
《九章算术》更相减损术【方田篇05-06】
正常函数写法:
int gcd(int a,int b)
{
while(a!=b)
{
if(a>b)
a-=b;
else
b-=a;
}
return b;
}
递归写法
int gcd(int m,int n)
{
if(m==n)
return n;
else if(m>n)
return gcd(n,m-n);
else
return gcd(m,n-m);
}
与辗转相除法的比较
1.手算方面,辗转相除法比更相减损法更简洁,因为辗转相除法使用除法,在迭代次数上要小于使用减法的更相减损法。
2.代码运行效率上来看,辗转相除法略优于更相减损法
可乐yue求:最大公约数不同算法的时间比较(辗转相除法,更相减损术等)
二、Stein算法
在查找更相减损术时发现的求最大公约数的新方法,它改进了辗转相除法与更相减损法。
算法内容
原理
1.当a和b均为偶数,gcb(a,b) = 2gcb(a/2, b/2) = 2 * gcb(a>>1, b>>1)
2.当a为偶数,b为奇数,gcb(a,b) = gcb(a/2, b) = gcb(a>>1, b)
3.当a为奇数,b为偶数,gcb(a,b) = gcb(a, b/2) = gcb(a, b>>1)
4.当a和b均为奇数,利用更相减损术运算一次,gcb(a,b) = gcb(b, a-b), 此时a-b的结果必然是偶数,又可以继续进行移位运算。
代码
int Stein(int x, int y)
{
if (x < y)
{
int tmp = x;
x = y;
y = tmp;
}
if ( x%y == 0)
{
return y;
}
if (x % 2 == 0 && y % 2 == 0)
{
return 2*Stein(x >> 1, y >> 1);
}
else if (x%2 == 0 && y%2 != 0)
{
return Stein(x >> 1, y);
}
else if (x % 2 != 0 && y % 2 == 0)
{
return Stein(x, y >> 1);
}
else if (x % 2 != 0 && y % 2 != 0)
{
return Stein(x, (x - y) >> 1);
}
优点
虽然代码较长,但Stein算法仍有优势
欧几里得算法在处理较小数字时优势是明显的,但对于大整数时,高精度的整除和取余运算就显得非常复杂,所以Stein算法的优点就在于只需要进行移位(位运算)和减法操作,处理高精度GCD问题时相对简便;
还是这张图,可以发现,输入数字越大,Stein算法的优势越明显
总结
辗转相除法,更相减损法,Stein算法各有优劣,从目前我们学习的进度来看,熟练掌握辗转相除法一种即可,但同时对Stein算法的也可以了解了解,便于将来处理大数。