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

【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 であることが示せます。つまり、解が存在する限り、この貪欲なペアリングは必ず正しい答えを導きます。

アルゴリズムの手順

  1. 配列Aのサイズをnとする。
  2. (値, インデックス) のペアを格納する配列pを用意し、すべての要素を設定する。
  3. pを昇順にソートする。
  4. 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) を使用します。

  1. C++で二分木のすべての右葉ノードの合計を求める3つの方法

    問題概要この記事では、C++ を使って二分木の中からすべての右葉ノード(親ノードの右側の子であり、かつ子ノードを持たないノード)を検出し、その値の合計を求める方法を解説します。まず、具体例で問題を確認してみましょう。入力:出力: 8説明:この木の右葉ノードは 1 と 7 合計 = 1 + 7 = 8上図の二分木では、ノード 4 の右の子である「1」と、ノード 6 の右の子である「7」が右葉ノードに該当します。したがって、合計は 1 + 7 = 8 となります。解法1: 再帰によるアプローチ最もシンプルな解決策は、木を根から葉へ向かって再帰的に走査する方法です。各ノードに対して、その右の子が葉ノ

  2. C++で二分木内のすべての左葉の合計を求める方法【再帰・DFS・BFSで解説】

    問題概要 この問題では、二分木が与えられ、その木に含まれるすべての「左葉(左の子である葉ノード)」の値の合計を求めることが課題となります。 具体例を使って問題を確認しましょう。 入力: 出力:11 説明− 木の左葉ノードは:2, 9 合計 = 2 + 9 = 11 ここで「左葉」とは、親ノードの左の子であり、かつ子を一切持たないノードを指します。上図の例では、ノード2とノード9がこの条件を満たすため、その合計値11が答えになります。 解決アプローチ 1:再帰 最もシンプルな解決策は、木をルートから葉へ向かって走査する方法です。走査の過程で、注目しているノードの左の子が葉ノードであ