C++
 Computer >> コンピューター >  >> プログラミング >> C++

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 の場合の流れを追ってみましょう。

  1. 12 >= 2×5 が成立するため、x = 12 % 10 = 2 となります。
  2. 次に 5 >= 2×2 が成立するため、y = 5 % 4 = 1 となります。
  3. 続いて 2 >= 2×1 が成立するため、x = 2 % 2 = 0 となります。
  4. x が 0 になったためループを終了し、「X: 0、Y: 1」が出力されます。

このように剰余演算を活用することで、1018 オーダーの巨大な入力に対しても高速に最終的な X と Y の値を求められる点が、このアルゴリズムの大きな強みです。

  1. 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、

  2. 行と列の最大値が指定されている場合に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 を配列