問題解決ノート(36)——最大公約数問題
2つの正の整数の最大公約数を求めます.
考え方:これはとても基本的な問題で、最もよく見られるのは2つの方法で、転がり相除算法と転がり相減算法です.一般式は、それぞれf(x,y)=f(y,x%y)、f(x,y)=f(y,x−y)(x>=y>0)である.一般式に基づいてアルゴリズムを書くのは難しくないが,ここでは与えない.ここでは「プログラミングの美しさ」のアルゴリズムを示し,主に反復の回数を減らすためである.
xおよびyについて,y=k*y 1,x=k*x 1の場合,f(x,y)=k*f(x 1,y 1)となる.また、x=p*x 1の場合、pは素数であり、y%p!=0で、f(x,y)=f(p*x 1,y)=f(x 1,y).p=2をとる.
参照コード:
次の非再帰バージョン:
考え方:これはとても基本的な問題で、最もよく見られるのは2つの方法で、転がり相除算法と転がり相減算法です.一般式は、それぞれf(x,y)=f(y,x%y)、f(x,y)=f(y,x−y)(x>=y>0)である.一般式に基づいてアルゴリズムを書くのは難しくないが,ここでは与えない.ここでは「プログラミングの美しさ」のアルゴリズムを示し,主に反復の回数を減らすためである.
xおよびyについて,y=k*y 1,x=k*x 1の場合,f(x,y)=k*f(x 1,y 1)となる.また、x=p*x 1の場合、pは素数であり、y%p!=0で、f(x,y)=f(p*x 1,y)=f(x 1,y).p=2をとる.
参照コード:
// :
// : x,y
// :
int gcd_solution1(int x, int y)
{
if(y == 0)
return x;
else if(x < y)
return gcd_solution1(y, x);
else
{
if(x&1) //x
{
if(y&1) //y
return gcd_solution1(y, x-y);
else //y
return gcd_solution1(x, y>>1);
}
else //x
{
if(y&1) //y
return gcd_solution1(x>>1, y);
else //y
return gcd_solution1(x>>1, y>>1) << 1;
}
}
}
次の非再帰バージョン:
int gcd_solution2(int x, int y)
{
int result = 1;
while(y)
{
int t = x;
if(x&1)
{
if(y&1)
{
x = y;
y = t % y;
}
else
y >>= 1;
}
else
{
if(y&1)
x >>= 1;
else
{
x >>= 1;
y >>= 1;
result <<= 1;
}
}
}
return result * x;
}