C++でインデックス間隔がk以上の最大合計部分列を求めるアルゴリズム
問題概要
サイズnの配列arr[]と整数kが与えられたとき、選んだ要素同士のインデックスがk以上離れている部分列の中で、合計が最大になるものを求めるプログラムを作成します。
問題の詳細
配列から要素を選んで部分列を構成します。このとき、選ばれた要素のインデックス同士は互いにk以上の距離を持つ必要があります。その条件を満たすすべての部分列の中から、合計値が最大となるものを見つけましょう。
入力例
arr[] = {2, 3, 7, 9, 2, 8, 3}
出力例
15
解説
条件を満たす部分列の例は以下の通りです。
{2, 9, 3} → 合計 = 14
{3, 2} → 合計 = 5
{7, 8} → 合計 = 15
この中で最大の合計値は15となります。
解法アプローチ
1. 単純な解法(全列挙)
最も基本的な方法は、条件を満たすすべての部分列を列挙し、それぞれの合計を計算して最大値を返すことです。しかし、部分列の候補数は組み合わせ爆発的に増加するため、配列が大きくなると現実的な時間内に計算できません。
2. 動的計画法(DP)による効率的な解法
効率を改善するには、動的計画法を活用します。「現在の位置までの最大合計」を格納する配列を用意し、配列の後ろから順に計算を進めます。
各要素iに対して、以下の2つの選択肢を比較します。
- 要素を合計に採用する場合: sum[i] = arr[i] + sum[i + k + 1]
- 要素を合計から除外する場合: sum[i] = sum[i + 1]
この2つのうち大きい方をsum[i]として記録し、最終的な答えとしてsum[0]を返します。
C++による実装例
#include <bits/stdc++.h>
using namespace std;
int calcMaxSubSeqSum(int arr[], int N, int k){
int maxSumDP[N];
maxSumDP[N - 1] = arr[N - 1];
for (int i = N - 2; i >= 0; i--) {
if (i + k + 1 >= N)
maxSumDP[i] = max(arr[i], maxSumDP[i + 1]);
else
maxSumDP[i] = max(arr[i] + maxSumDP[i + k + 1], maxSumDP[i + 1]);
}
return maxSumDP[0];
}
int main() {
int N = 10, k = 2;
int arr[] = { 50, 70, 40, 50, 90, 70, 60, 40, 70, 50 };
cout << "The maximum sum subsequence with at-least k distant elements is " << calcMaxSubSeqSum(arr, N, k);
return 0;
}
実行結果
The maximum sum subsequence with at-least k distant elements is 230
計算量の評価
この動的計画法による解法は、配列を後ろから一度だけ走査するため、時間計算量はO(N)です。また、最大合計を保持する補助配列が必要なため、空間計算量もO(N)となります。全列挙を行う単純な解法と比べて大幅な高速化が実現でき、大きな入力に対しても実用的に動作します。
-
C++で解く「最大和減少部分列」問題 ― 動的計画法による実装方法を徹底解説
はじめに 本記事では、N個の整数からなる配列 arr[] が与えられたとき、その中から厳密に減少する部分列を抜き出し、要素の合計が最大になる値(最大和減少部分列)をC++で求める方法を解説します。 問題の概要 配列の中から要素を選び、選んだ順序が左から右へ単調減少となるように部分列を作ります。そのとき、部分列の要素の合計として考えられる最大値を求めるのが目的です。 具体例で確認してみましょう。 入力例 arr[] = {3, 1, 6, 10, 5, 2, 9} 出力例 17 解説 この場合、合計が最大となる減少部分列は {10, 5, 2} です。10 + 5 + 2 = 17 が答えとな
-
C++で最大和の交互部分列を求めるアルゴリズムと実装方法
はじめに本記事では、C++を用いて「最大和の交互部分列(Alternating Subsequence)」を求めるプログラムについて解説します。ここで扱う問題は、整数型の配列が与えられたとき、その中から「減少→増加→減少→…」というように増減が交互に入れ替わる部分列を抜き出し、その要素の合計値が最大となるものを見つけるというものです。アルゴリズムの考え方この問題は動的計画法(DP)を用いて解くことができます。具体的には、以下の2つの配列を用意します。dec[i]: i番目の要素で終わる交互部分列のうち、「直前の操作が減少」である場合の最大和inc[i]: i番目の要素で終わる交互部分列のうち、