3つ連続しない条件での最大部分列の合計をC++で解く方法
本記事では、「同じ位置の要素を3つ連続して選ばない」という制約のもとで、数列から選んだ要素の合計を最大化する問題を解くプログラムについて解説します。
具体的には、正の整数列が与えられたとき、部分列として要素を選んでいく過程で3つ連続した要素を同時に選ぶことはできません。この条件下で実現できる合計値の最大値を求めるのが目的です。
動的計画法によるアプローチ
この問題は動的計画法(DP)を用いることで効率的に解くことができます。位置 i までの最大合計を sum[i] とするとき、i 番目の要素の扱い方は以下の3通りに分けられます。
- i 番目を選ばない場合: sum[i-1]
- i 番目だけを選ぶ場合(i-1 番目は選ばない): sum[i-2] + arr[i]
- i 番目と i-1 番目の両方を選ぶ場合(i-2 番目は選ばない): arr[i] + arr[i-1] + sum[i-3]
これら3つの候補の中から最大値を sum[i] として記録していき、最終的な sum[n-1] が答えとなります。計算量は O(n)、必要なメモリも O(n) であり、全探索よりもはるかに高速に処理できます。
C++での実装例
#include <bits/stdc++.h>
using namespace std;
// 3つ連続の数字を含まない最大部分列の合計を返す
int maxSumWO3Consec(int arr[], int n) {
int sum[n];
if (n >= 1) sum[0] = arr[0];
if (n >= 2) sum[1] = arr[0] + arr[1];
if (n > 2) sum[2] = max(sum[1], max(arr[1] + arr[2], arr[0] + arr[2]));
for (int i = 3; i < n; i++)
sum[i] = max(max(sum[i - 1], sum[i - 2] + arr[i]),
arr[i] + arr[i - 1] + sum[i - 3]);
return sum[n - 1];
}
int main() {
int arr[] = { 100, 1000 };
int n = sizeof(arr) / sizeof(arr[0]);
cout << maxSumWO3Consec(arr, n);
return 0;
}
出力結果
1100
コードの解説
初期化部分では、配列の長さが1の場合は最初の要素そのものが答えになり、長さが2の場合は2つの要素の合計がそのまま答えになります。これは2つまでなら連続して選んでもよいというルールのためです。長さが3以上の場合は、3つのうち少なくとも1つは必ず除外されるため、その組み合わせごとの最大値を計算します。
サンプル入力 {100, 1000} の場合、要素は2つしかないため両方を選ぶことが可能で、合計は 100 + 1000 = 1100 となります。
-
【C++】循環配列で隣接しない要素を選んだときの最大合計を求める方法
問題の概要本記事では、循環配列 cirArr[] が与えられたとき、「どの2つの要素も隣接して選ばない」という条件を満たす要素の最大合計を求めるプログラムをC++で作成します。問題の詳細循環配列に対して、隣接する要素を同時に選ぶことができない、つまり要素を一つ飛ばしで選択した場合の最大合計を求める必要があります。循環配列とは、配列の末尾の要素が先頭の要素につながっている特殊な配列構造のことです。具体例で問題を確認しましょう。入力例cirArr[] = {4, 1, 5, 3, 2}出力例9解説最大の合計となる循環部分列は [4, 5, 2] で、その合計は 9 になります。解決アプローチこの問
-
C++で解説:隣接する2数は互いに素でなく、連続する3数は互いに素となる数列を出力するプログラム
はじめに このチュートリアルでは、「隣接する2つの数が互いに素ではなく、かつ連続する3つの数が互いに素となる」ような数列を出力するC++プログラムについて解説します。 問題の概要 整数Nが与えられたとき、109未満のN個の整数を出力する必要があります。出力する数列は、以下の2つの条件を満たさなければなりません。 条件1: 隣接する2つの数は互いに素でない(最大公約数が1より大きい) 条件2: 連続する3つの整数の組は互いに素である(最大公約数が1) 例えば、N=4が与えられた場合、両方の条件を満たす数列は次のようになります。 6 15 35 14 この出力を検証してみましょう。 gcd(