C++で最大和ビトニック部分列を求める方法【動的計画法で解説】
この問題では、整数の配列 arr[] が与えられ、C++ を使って「最大和ビトニック部分列(Maximum Sum Bitonic Subsequence)」を求めるプログラムを作成します。
ビトニック部分列(Bi-tonic subsequence)とは、要素がまず増加し続け、途中から減少に転じるという特性を持つ特別な部分列のことです。
問題を理解するための例
入力
arr[] = {4, 2, 3, 7, 9, 6, 3, 5, 1}
出力
33
説明
合計が最大となるビトニック部分列は {2, 3, 7, 9, 6, 5, 1} です。
合計 = 2 + 3 + 7 + 9 + 6 + 5 + 1 = 33
解法のアプローチ
最大和ビトニック部分列を効率よく求めるために、incSeq[] と decSeq[] という2つの補助配列を用意します。
- incSeq[i]: インデックス i を終点とする、arr[0...i] の範囲で厳密に増加する部分列の最大合計
- decSeq[i]: インデックス i を始点とする、arr[i...n-1] の範囲で厳密に減少する部分列の最大合計
すべての計算が終わったら、(incSeq[i] + decSeq[i] - arr[i]) の最大値を maxSum として返します。arr[i] を引く理由は、ビトニック列の頂点となる要素 arr[i] が incSeq と decSeq の両方に含まれ、二重に加算されてしまうためです。
このアルゴリズムの計算量は O(N²)、必要な追加メモリは O(N) です。
実装例
上記の解法を示すプログラムは以下のとおりです。
#include <iostream>
using namespace std;
int calcMaxVal(int a, int b){
if(a > b)
return a;
return b;
}
int findMaxSumBiTonicSubSeq(int arr[], int N){
int maxSum = -1;
int incSeq[N], decSeq[N];
for (int i = 0; i < N; i++){
decSeq[i] = arr[i];
incSeq[i] = arr[i];
}
for (int i = 1; i < N; i++)
for (int j = 0; j < i; j++)
if (arr[i] > arr[j] && incSeq[i] < incSeq[j] + arr[i]) incSeq[i] = incSeq[j] + arr[i];
for (int i = N - 2; i >= 0; i--)
for (int j = N - 1; j > i; j--)
if (arr[i] > arr[j] && decSeq[i] < decSeq[j] + arr[i])
decSeq[i] = decSeq[j] + arr[i];
for (int i = 0; i < N; i++)
maxSum = calcMaxVal(maxSum, (decSeq[i] + incSeq[i] - arr[i]));
return maxSum;
}
int main(){
int arr[] = {4, 2, 3, 7, 9, 6, 3, 5, 1};
int N = sizeof(arr) / sizeof(arr[0]);
cout<<"The Maximum Sum of Bi-tonic subsequence is : "<<findMaxSumBiTonicSubSeq(arr, N);
return 0;
}
出力
The Maximum Sum of Bi-tonic subsequence is : 33
-
C++のプレフィックス和(累積和)を活用してO(n)で最大部分配列和を求める方法
問題概要 正の整数と負の整数が混在する配列が与えられたとき、その配列の中で合計値が最大となる部分配列(連続した要素の並び)の合計を求める問題です。 例 入力配列が {-12, -5, 4, -1, -7, 1, 8, -3} の場合、合計が最大になる部分配列は {1, 8} となるため、出力は 9 になります。 アルゴリズム この問題は、プレフィックス和(累積和)を利用することで O(n) の時間計算量で効率的に解くことができます。考え方の核心は、「ある位置 i で終わる部分配列の合計の最大値」は「prefix_sum[i] から、それ以前に現れた最小の累積和を引いた値」で表せるという点です
-
C++で配列の最大平衡和(イクリブリアム・サム)を求める方法
問題概要配列 arr[] が与えられたとき、あるインデックス i における「接頭辞和(プレフィックスサム)」と「接尾辞和(サフィックスサム)」が一致する値の中から、最大値を見つけるのがこの問題の目的です。この一致する値は「平衡和(イクリブリアム・サム)」と呼ばれます。例入力配列が以下の場合を考えてみましょう。Arr[] = {1, 2, 3, 5, 3, 2, 1}このとき出力は 11 になります。その理由は次の通りです。接頭辞和 = arr[0..3] = 1 + 2 + 3 + 5 = 11接尾辞和 = arr[3..6] = 5 + 3 + 2 + 1 = 11インデックス 3 を境にし