C++でN個の数値から作るN/2ペアの平方和を最小化するアルゴリズム
問題概要
n個の要素を持つ配列が与えられたとき、その要素を使ってn/2個のペアを作成し、各ペアの合計値を2乗したものの総和(平方和)が最小になるようにするのが課題です。
例
次の配列が与えられたとします。
arr[] = {5, 10, 7, 4}この場合、(4, 10) と (5, 7) のようにペアを作ると、平方和は最小値の 340 になります。
計算内容は以下の通りです。
- (4 + 10)² = 14² = 196
- (5 + 7)² = 12² = 144
- 196 + 144 = 340
アルゴリズム
最小の平方和を求めるための手順は以下の通りです。
- 配列を昇順にソートする
- 配列の先頭と末尾を指す2つの変数(start と end)を用意する
- 次のように合計を計算する:
sum = arr[start] + arr[end];
sum = sum * sum; - start < end である限りこの手順を繰り返し、minSum に加算していく
While (start < end) {
sum = arr[start] + arr[end];
sum = sum * sum;
minSum += sum;
++start;
--end;
}なぜこの方法が有効か
数直線上で考えると、大きな数同士や小さな数同士をペアにすると合計値が大きくなり、その2乗はさらに大きく膨らみます。一方、ソート後に「最小値+最大値」の組み合わせでペアを作ると、各ペアの合計値が平均的に近づき、2乗和を最小化できます。これは数学的にも証明されている有名なテクニックです。
C++での実装例
#include <iostream>
#include <algorithm>
#define SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
using namespace std;
int getMinSquareSum(int *arr, int n) {
sort(arr, arr + n);
int minSum = 0;
int start = 0;
int end = n - 1;
while (start < end) {
int sum = arr[start] + arr[end];
sum *= sum;
minSum += sum;
++start;
--end;
}
return minSum;
}
int main() {
int arr[] = {5, 10, 7, 4};
int res = getMinSquareSum(arr, SIZE(arr));
cout << "Minimum square sum: " << res << "\n";
return 0;
}出力結果
上記のプログラムをコンパイルして実行すると、以下の出力が得られます。
Minimum square sum: 340
計算量について
このアルゴリズムの時間計算量は、ソート処理が支配的となるため O(n log n) です。ペアを作成するループ部分自体は O(n/2)、つまり O(n) で済みます。また、追加のメモリ領域をほとんど必要としないため、空間計算量は O(1) と非常に効率的です。
-
最初のn個の自然数の二乗和を求めるC++プログラムの解説
はじめにこの記事では、最初のn個の自然数(1からnまで)の二乗和を求める方法について解説します。例えば、n = 4 の場合、計算結果は 1² + 2² + 3² + 4² = 1 + 4 + 9 + 16 = 30 となります。基本的なアプローチとしては、1からnまで繰り返すforループを使用し、各ステップで項の二乗を計算して合計に加算していく方法があります。このプログラムの計算量は O(n) です。しかし、O(1) の定数時間で解きたい場合は、次の級数の公式を利用できます。Σk² = n(n + 1)(2n + 1) / 6この公式を使えば、ループ処理を行わずに一発で答えを求めることが可能で
-
1/1! + 2/2! + 3/3! + …… + n/n! の級数の合計を求めるPythonプログラム
この記事では、与えられた問題を解くための解法とアプローチについて詳しく解説します。 問題文 整数 n が入力として与えられたとき、次の級数の合計を求めます。 1/1! + 2/2! + 3/3! + 4/4! + …… + n/n! ここでは for ループを使用して実装するため、時間計算量は O(n) となります。また、処理効率を高めるポイントとして、階乗の計算を同じループ内で同時に行っている点が挙げられます。 アルゴリズム 以下の手順で級数の合計を求めます。 合計値 res を 0、階乗値 fact を 1 で初期化します。 i を 1 から n まで順に処理し、fact *= i に