【C++】全プレイヤーの合計が等しくなるようにカードを配る方法を見つけるコード
問題概要
n個の要素からなる配列Aがあるとします。ここでnは偶数であり、A[i]はi番目のカードに書かれた数値を表します。ゲームにはn/2人のプレイヤーが参加し、開始時に各プレイヤーは2枚のカードを受け取ります。このとき、どのプレイヤーの手元でも、2枚のカードに書かれた数値の合計が等しくなるようにカードを配分する方法を見つける必要があります。
例えば、入力が A = [1, 5, 7, 4, 4, 3] の場合、出力は [(0, 2), (5, 1), (3, 4)] となります。これは A[0] + A[2] = 8、A[5] + A[1] = 8、A[3] + A[4] = 8 となり、全員の合計が8で一致するためです。
解法のアプローチ
この問題は「貪欲法(グリーディ法)」で解くことができます。ポイントは以下のとおりです。
- 各カードを「値」と「元のインデックス」のペアとして管理する。
- ペアの配列を値の昇順にソートする。
- ソート後、最も小さい値のカードと最も大きい値のカードを順にペアにしていく(i番目と n−i−1 番目を組み合わせる)。
なぜ最小値と最大値を組ませると正しいのか
直感的には「小さい数と大きい数を組み合わせると平均に近づく」ことが分かります。厳密に考えると、等しい合計となる配り方が存在する場合、その合計をSとすると、最小値mのパートナーは必ずS−m、最大値MのパートナーはS−Mになります。ここで x ≤ M、y ≥ m より、S = m + x ≤ m + M ≤ M + y = S が成り立ち、m + M = S であることが示せます。つまり、解が存在する限り、この貪欲なペアリングは必ず正しい答えを導きます。
アルゴリズムの手順
- 配列Aのサイズをnとする。
- (値, インデックス) のペアを格納する配列pを用意し、すべての要素を設定する。
- pを昇順にソートする。
- i = 0 から n/2 − 1 までループし、p[i].second(インデックス)と p[n − i − 1].second をペアとして出力する。
C++での実装例
理解を深めるために、以下の実装を見てみましょう。
#include <bits/stdc++.h>
using namespace std;
void solve(vector<int> A){
int n = A.size();
pair<int, int> p[n];
for (int i = 0; i < n; i++){
p[i].first = A[i];
p[i].second = i;
}
sort(p, p + n);
for (int i = 0; i < n / 2; i++)
cout << "(" << p[i].second << ", " << p[n - i - 1].second << "), ";
}
int main(){
vector<int> A = { 1, 5, 7, 4, 4, 3 };
solve(A);
}実行結果
入力:
{ 1, 5, 7, 4, 4, 3 }出力:
(0, 2), (5, 1), (3, 4),
計算量
ソートに O(n log n)、ペアリングのループに O(n/2) かかるため、全体の時間計算量は O(n log n) です。また、ペア配列の分だけ追加の記憶領域として O(n) を使用します。
-
C++で二分木のすべての右葉ノードの合計を求める3つの方法
問題概要この記事では、C++ を使って二分木の中からすべての右葉ノード(親ノードの右側の子であり、かつ子ノードを持たないノード)を検出し、その値の合計を求める方法を解説します。まず、具体例で問題を確認してみましょう。入力:出力: 8説明:この木の右葉ノードは 1 と 7 合計 = 1 + 7 = 8上図の二分木では、ノード 4 の右の子である「1」と、ノード 6 の右の子である「7」が右葉ノードに該当します。したがって、合計は 1 + 7 = 8 となります。解法1: 再帰によるアプローチ最もシンプルな解決策は、木を根から葉へ向かって再帰的に走査する方法です。各ノードに対して、その右の子が葉ノ
-
C++で二分木内のすべての左葉の合計を求める方法【再帰・DFS・BFSで解説】
問題概要 この問題では、二分木が与えられ、その木に含まれるすべての「左葉(左の子である葉ノード)」の値の合計を求めることが課題となります。 具体例を使って問題を確認しましょう。 入力: 出力:11 説明− 木の左葉ノードは:2, 9 合計 = 2 + 9 = 11 ここで「左葉」とは、親ノードの左の子であり、かつ子を一切持たないノードを指します。上図の例では、ノード2とノード9がこの条件を満たすため、その合計値11が答えになります。 解決アプローチ 1:再帰 最もシンプルな解決策は、木をルートから葉へ向かって走査する方法です。走査の過程で、注目しているノードの左の子が葉ノードであ