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

C++で最小公倍数(LCM)がNとなる相異なる数の最大合計を求める方法

この記事では、与えられた整数Nに対して、それらの数の最小公倍数(LCM)がNとなるような相異なる数を選んだときの合計の最大値を求めるプログラムを、C++で実装する方法を解説します。

問題の概要

一見複雑に思えるこの問題ですが、実は答えは「Nのすべての約数の合計」になります。なぜなら、Nの約数全体を集めた集合の最小公倍数は必ずNとなり、これ以上大きい合計は得られないからです。したがって、Nの相異なる約数をすべて足し合わせた値が最大合計となります。

具体例を使って問題を確認してみましょう。

入力

N = 12

出力

28

説明

N = 12 の相異なる約数は 1, 2, 3, 4, 6, 12 の6つです。
合計 = 1 + 2 + 3 + 4 + 6 + 12 = 28

解法アプローチ

最もシンプルな解決策は、Nのすべての約数を見つけ出し、それらをすべて加算することです。

ここで重要なのは効率化のポイントです。約数はペアで存在する(例えば12の場合、2と6のような組み合わせ)ため、1から√Nまでの範囲だけでループすれば十分です。具体的には以下の手順で処理します。

  • 1から√Nまでの各数iについて、Nがiで割り切れるかどうかを確認します。
  • 割り切れる場合、i と N/i が異なるなら、両方を合計に加算します。
  • i と N/i が等しい場合(i² = N の場合)、重複を避けるために i を1回だけ加算します。

この手法により、O(√N) の計算量で約数の総和を効率的に求めることができます。

実装例

以下は、この解法の動作を示すC++プログラムです。

#include <iostream>
using namespace std;
int calcMaxSumForLCM(int N){
    int maxSum = 0;
    for (int i = 1; i*i <= N; i++){
        if (N%i == 0){
            if (i == (N/i))
                maxSum = maxSum + i;
            else
                maxSum = maxSum + i + (N/i);
        }
    }
    return maxSum;
}
int main(){
    int N = 17;
    cout<<"最小公倍数が "<<N<<" となる相異なる数の合計の最大値は "<<calcMaxSumForLCM(N)<<" です";
    return 0;
}

出力

最小公倍数が 17 となる相異なる数の合計の最大値は 18 です

この例ではN=17が素数であるため、約数は1と17のみとなり、合計は18になります。素数の場合は常に「1 + N」という結果になることも覚えておくと良いでしょう。

  1. 【C++】部分木がBSTでもある二分木における最大部分木合計の求め方

    問題概要 この問題では、二分木 BT が与えられ、「その部分木自身も二分探索木(BST)である」という条件を満たす部分木の中から、ノード値の合計が最大となるものを見つけるプログラムを作成します。 二分木(Binary Tree)とは 二分木とは、各ノードが最大2つの子ノードを持つことができる特殊な木構造です。 二分探索木(BST)とは 二分探索木とは、すべてのノードが以下の性質を満たす木のことです。 左部分木のキー値は、親(ルート)ノードのキー値より小さい。 右部分木のキー値は、親(ルート)ノードのキー値以上である。 入出力例 入力: 出力: 32 説明:この木には BST として成立し

  2. 【C++】循環配列で隣接しない要素を選んだときの最大合計を求める方法

    問題の概要本記事では、循環配列 cirArr[] が与えられたとき、「どの2つの要素も隣接して選ばない」という条件を満たす要素の最大合計を求めるプログラムをC++で作成します。問題の詳細循環配列に対して、隣接する要素を同時に選ぶことができない、つまり要素を一つ飛ばしで選択した場合の最大合計を求める必要があります。循環配列とは、配列の末尾の要素が先頭の要素につながっている特殊な配列構造のことです。具体例で問題を確認しましょう。入力例cirArr[] = {4, 1, 5, 3, 2}出力例9解説最大の合計となる循環部分列は [4, 5, 2] で、その合計は 9 になります。解決アプローチこの問