C++で指定した条件に基づいて変化させたときの最終的なXとYの値を求める方法
2つの正の整数 X と Y の初期値が与えられているとします。以下の手順に従って値を変化させていったとき、最終的に残る X と Y の値を求めるのが本記事のテーマです。
処理のルール
- ステップ1:X = 0 かつ Y = 0 の場合は処理を終了します。それ以外の場合はステップ2へ進みます。
- ステップ2:X >= 2Y が成立する場合は X = X − 2Y としてステップ1へ戻ります。成立しない場合はステップ3へ進みます。
- ステップ3:Y >= 2X が成立する場合は Y = Y − 2X としてステップ1へ戻ります。どちらの条件も成立しない場合は処理を終了します。
効率化のポイント
X と Y は最大 1018 という非常に大きな値を取りうるため、減算を1回ずつ繰り返す単純な総当たり(ブルートフォース)では計算時間が膨大になり、現実的ではありません。
そこで注目するのが、「同じ条件が連続して成立する間は減算が何度も繰り返される」という性質です。例えば X >= 2Y の間、X から 2Y を引き続ける操作は、剰余演算を使った「X = X % (2Y)」と完全に等価になります。これにより、巨大な値でもわずか数ステップで最終値まで到達できます。
C++による実装例
#include<iostream>
using namespace std;
void alterNumber(long long x, long long y) {
while (1) {
if (x == 0 || y == 0)
break;
if (x >= 2 * y)
x = x % (2 * y);
else if (y >= 2 * x)
y = y % (2 * x);
else
break;
}
cout << "X: " << x << "\n" << "Y: " << y;
}
int main() {
long long x = 12, y = 5;
alterNumber(x, y);
}出力結果
X: 0 Y: 1
コードの解説
alterNumber 関数は、無限ループの中で3つの条件を順に判定します。
- X または Y が 0 になった時点でループを抜けます。
- X >= 2Y の場合は、減算の繰り返しを剰余演算 x % (2Y) で一括処理します。
- Y >= 2X の場合も同様に、y % (2X) で一括処理します。
- どちらの条件も満たさない場合は、それ以上変化が起こらないため終了します。
入力例 x = 12、y = 5 の場合の流れを追ってみましょう。
- 12 >= 2×5 が成立するため、x = 12 % 10 = 2 となります。
- 次に 5 >= 2×2 が成立するため、y = 5 % 4 = 1 となります。
- 続いて 2 >= 2×1 が成立するため、x = 2 % 2 = 0 となります。
- x が 0 になったためループを終了し、「X: 0、Y: 1」が出力されます。
このように剰余演算を活用することで、1018 オーダーの巨大な入力に対しても高速に最終的な X と Y の値を求められる点が、このアルゴリズムの大きな強みです。
-
C++でLCMとHCFが与えられたときにもう一方の数を求める方法
ある数Aと、その最小公倍数(LCM)および最大公約数(HCF/GCD)の値が与えられているとき、もう一方の数Bを求める問題を考えます。例えば、A = 5、LCM = 25、HCF = 4が与えられた場合、もう一方の数は20になります。この問題を解く鍵となるのは、任意の2つの数AとBの間に常に成り立つ次の重要な数学的性質です。$$𝐴∗𝐵=𝐿𝐶𝑀∗𝐻𝐶𝐹$$つまり、「2つの数の積」は「最小公倍数と最大公約数の積」と等しくなります。この式をBについて変形すると、次のようになります。$$𝐵= \frac{LCM*HCF}{A}$$アルゴリズム数A、LCM、
-
行と列の最大値が指定されている場合にPythonで元の行列を復元する方法
問題の概要サイズNの配列AとサイズMの配列B、さらにN×Mの2値行列が与えられているとします。この2値行列では、「1」は元の行列の対応する位置に正の整数が存在していたことを示し、「0」はその位置が元の行列でも0であったことを示します。私たちの課題は、A[i]がi行目の最大要素となり、B[j]がj列目の最大要素となるような元の行列を復元することです。例えば、入力が A = [4, 2, 3]、B = [3, 1, 0, 0, 4, 0, 5] の場合、復元される行列は以下の出力例のようになります。解法のアプローチこの問題を解くためには、以下の手順に従います。N を配列AのサイズとしますM を配列