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

C++の動的計画法を用いて二分木内の互いに隣接しないノードの最大合計を求める方法

この問題では、各ノードに値が設定された二分木が与えられます。動的計画法(DP)を活用し、選択したノード同士が互いに隣接しないという条件下で、二分木のノード値の合計として考えられる最大値を求めるプログラムを作成することが課題です。

問題の詳細

二分木の中からノードの部分集合を選び、合計値を最大化します。ただし、選んだノード同士が直接的な親子関係でつながっていてはなりません。つまり、あるノードを選んだ場合、その親ノードおよび子ノードは選択できないという制約があります。

入力例

C++の動的計画法を用いて二分木内の互いに隣接しないノードの最大合計を求める方法

出力例

24

解説

この例では、合計に含めるノードは以下のとおりです。

8 + 5 + 9 + 2 = 24

解法のアプローチ

この問題は、マップ(連想配列)を活用しながら、最大合計(maxSum)を構成するノードの和を求めることで解決できます。制約条件により、あるノードとその子ノードを同時に合計へ含めることはできません。そのため、あるノードを合計に加えるかどうかを判断する前に、その子の部分木により大きな合計を形成する要素が存在しないかを確認する必要があります。

また、各ノードについて同じ親子部分木の合計を何度も再計算すると、計算コストが増大してしまいます。そこでメモ化を利用し、各ノードまでの最大合計をマップに保存しておくことで、一度計算した結果を後から再利用できるようにします。

実装例

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

#include <bits/stdc++.h>
using namespace std;
struct node{
   int data;
   struct node *left, *right;
};
struct node* newNode(int data){
   struct node *temp = new struct node;
   temp->data = data;
   temp->left = temp->right = NULL;
   return temp;
}
int findMaxSumBT(node* node, map<struct node*, int>& nodeSum);
int sumSubTreeNodes(node* node, map<struct node*, int>& nodeSum){
   int maxSum = 0;
   if (node->left)
      maxSum += findMaxSumBT(node->left->left, nodeSum) + findMaxSumBT(node->left->right, nodeSum);
   if (node->right)
      maxSum += findMaxSumBT(node->right->left, nodeSum) + findMaxSumBT(node->right->right, nodeSum);
   return maxSum;
}
int findMaxSumBT(node* node, map<struct node*, int>& nodeSum){
   if (node == NULL)
      return 0;
   if (nodeSum.find(node) != nodeSum.end())
      return nodeSum[node];
   int sumInclCurr = node->data + sumSubTreeNodes(node, nodeSum);
   int sumExclCurr = findMaxSumBT(node->left, nodeSum) + findMaxSumBT(node->right, nodeSum);
   nodeSum[node] = max(sumInclCurr, sumExclCurr);
   return nodeSum[node];
}
int main(){
   node* root = newNode(9);
   root->left = newNode(4);
   root->right = newNode(7);
   root->left->left = newNode(8);
   root->left->right = newNode(5);
   root->right->left = newNode(2);
   map<struct node*, int> nodeSum;
   cout << "Maximum sum of nodes in Binary tree such that no two are adjacent using Dynamic Programming is " << findMaxSumBT(root, nodeSum);
   return 0;
}

出力

Maximum sum of nodes in Binary tree such that no two are adjacent using Dynamic Programming is 24
  1. 【C++】循環配列で隣接しない要素を選んだときの最大合計を求める方法

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

  2. C++で二分木の奇数レベルにあるノードを出力するプログラム

    このチュートリアルでは、与えられた二分木(バイナリツリー)の中から、奇数レベルに存在するノードを出力するC++プログラムについて解説します。 本プログラムでは、ルートノードのレベルを「1」と定義し、それ以降のレベルは交互にカウントしていきます。つまり、レベル1・3・5…といった奇数番目の階層に属するノードが出力の対象となります。 例として、以下のような二分木が与えられた場合を考えてみましょう。 この二分木の場合、奇数レベルに存在するノードは 1, 4, 5, 6 となります。 アルゴリズムの考え方 実装には再帰呼び出しを利用します。ルートから探索を開始し、現在のレベルが奇数かどうかをブール