【C++】隣り合う2段が同時に黄色にならないように階段を2色で塗る方法の総数を求める
n個の階段と、それらを塗るための2色(赤・黄)が与えられます。この記事では、「隣り合う2段がどちらも黄色にならない」という条件を満たしながら階段を塗る方法が何通りあるのかを数える問題を、C++で解いていきます。
まずは具体例で問題の内容を確認してみましょう。
入力例
3
出力例
5
説明
条件を満たす塗り方は「YRY」「RYR」「YRR」「RRY」「RRR」の5通りです。ここで R は赤色、Y は黄色を表します。
規則性を見つける
この問題を解くために、段数が増えたときの塗り方の数を順番に観察してみましょう。
- N = 1 のとき、ways(1) = 2:R、Y
- N = 2 のとき、ways(2) = 3:RY、YR、RR
- N = 3 のとき、ways(3) = 5:RYR、YRY、RRY、YRR、RRR
- N = 4 のとき、ways(4) = 8:YRYR、RYRY、RYRR、YRRY、YRRR、RRYR、RRRR、RRRY
これらの結果から、塗り方の総数は「初項が2、第2項が3」のフィボナッチ数列として求められることが分かります。
なぜフィボナッチ数列になるのか
理由はシンプルです。n段目を赤で塗る場合、直前の段が何色でも制約に違反しないため、そこまでの(n-1)段の塗り方は ways(n-1) 通りあります。一方、n段目を黄で塗る場合は、(n-1)段目が必ず赤でなければならないため、その組み合わせは ways(n-2) 通りになります。よって次の漸化式が成り立ちます。
ways(n) = ways(n-1) + ways(n-2)
C++での実装例
このロジックをそのままプログラムにすると、以下のようになります。
#include <iostream>
using namespace std;
int colorSteps(int n) {
int first = 2;
int next = 3;
for (int i = 3; i <= n; i++) {
next = first + next;
first = next - first;
}
return next;
}
int main(){
int n = 6;
cout<<"Number of ways to color "<<n<<" steps is "<<colorSteps(n);
return 0;
}
実行結果
Number of ways to color 6 steps is 21
このプログラムはループで一度ずつ計算を進めていくだけなので、時間計算量は O(n)、追加のメモリも定数 O(1) で済む、非常に効率的な解法となっています。
-
C++の動的計画法を用いて二分木内の互いに隣接しないノードの最大合計を求める方法
この問題では、各ノードに値が設定された二分木が与えられます。動的計画法(DP)を活用し、選択したノード同士が互いに隣接しないという条件下で、二分木のノード値の合計として考えられる最大値を求めるプログラムを作成することが課題です。 問題の詳細 二分木の中からノードの部分集合を選び、合計値を最大化します。ただし、選んだノード同士が直接的な親子関係でつながっていてはなりません。つまり、あるノードを選んだ場合、その親ノードおよび子ノードは選択できないという制約があります。 入力例 出力例 24 解説 この例では、合計に含めるノードは以下のとおりです。 8 + 5 + 9 + 2 = 24 解法のアプ
-
【C++】循環配列で隣接しない要素を選んだときの最大合計を求める方法
問題の概要本記事では、循環配列 cirArr[] が与えられたとき、「どの2つの要素も隣接して選ばない」という条件を満たす要素の最大合計を求めるプログラムをC++で作成します。問題の詳細循環配列に対して、隣接する要素を同時に選ぶことができない、つまり要素を一つ飛ばしで選択した場合の最大合計を求める必要があります。循環配列とは、配列の末尾の要素が先頭の要素につながっている特殊な配列構造のことです。具体例で問題を確認しましょう。入力例cirArr[] = {4, 1, 5, 3, 2}出力例9解説最大の合計となる循環部分列は [4, 5, 2] で、その合計は 9 になります。解決アプローチこの問