C++ですべての部分配列から最小のLCMとGCDを求める方法
サイズNの正の整数からなる配列 arr が与えられたとき、考えられるすべての部分配列の中で最小のLCM(最小公倍数)とGCD(最大公約数)を求める問題を考えてみましょう。例えば、配列が {2, 66, 14, 521} である場合、最小のLCMは 2、最小のGCDは 1 となります。
解き方のアプローチ
この問題は貪欲法(グリーディーアプローチ)を用いて効率的に解くことができます。ポイントは次の2点です。
- 部分配列に含まれる要素数を減らすほど、LCMは小さくなる傾向があります。
- 逆に、部分配列のサイズを大きくするほど、GCDは小さくなります。
したがって、求めるべき最小のLCMは「配列内の最小の要素」(単一要素からなる部分配列)となり、最小のGCDは「配列全体のすべての要素のGCD」となります。
C++による実装例
#include <iostream>
#include <algorithm>
using namespace std;
int minimum_gcd(int arr[], int n) {
int GCD = 0;
for (int i = 0; i < n; i++)
GCD = __gcd(GCD, arr[i]);
return GCD;
}
int minimum_lcm(int arr[], int n) {
int LCM = arr[0];
for (int i = 1; i < n; i++)
LCM = min(LCM, arr[i]);
return LCM;
}
int main() {
int arr[] = { 2, 66, 14, 521 };
int n = sizeof(arr) / sizeof(arr[0]);
cout << "LCM: " << minimum_lcm(arr, n) << ", GCD: " << minimum_gcd(arr, n);
}実行結果
LCM: 2, GCD: 1
このように、minimum_lcm 関数では配列を走査して最小値を求め、minimum_gcd 関数ではすべての要素を順番にGCD計算することで答えを得られます。どちらの処理もO(N)の計算量で実行できるため、非常に効率的な解法といえます。
-
C++で木構造の全ノードに情報を伝播させるための最小反復回数を求める方法
本記事では、n個のノードからなる木構造(ツリー)データ構造が与えられたとき、根ノード(root)からすべてのノードへ情報を行き渡らせるために必要な最小反復回数を求めるアルゴリズムを解説します。 与えられる木には根ノードがあり、各ノードは任意の数の子を持つことができます。ここで重要なルールは、1回の反復につき、あるノードはその子のうち1つにのみ情報を伝えられるという点です。ただし、子ノードがさらにその子へ情報を渡している間も、根ノードは別の子へ情報を渡し続けることができます。この並行性を考慮して、全ノードへの伝達完了までに必要な最小回数を計算します。 入出力シナリオの例 例1: 入力:
-
C++で木の中のすべてのリンゴを収集するための最小時間を求める
問題概要 n個の頂点からなる無向木を考えます。頂点には0からn-1までの番号が付けられており、いくつかの頂点にはリンゴが置かれています。木の1つの辺を移動するのに1秒かかるとき、頂点0から出発してすべてのリンゴを集め、再び頂点0に戻るまでに必要な最小時間(秒)を求めてください。 無向木の辺は配列 edges として与えられ、edges[i] = [from_i, to_i] は頂点 from_i と頂点 to_i を結ぶ辺が存在することを表します。さらに、hasApple というブール値の配列も与えられ、hasApple[i] = true の場合は頂点 i にリンゴが存在し、false の