C++で解く「最も高いビルボード」問題 ― 動的計画法によるアプローチ
ビルボードを設置する際、その高さはできるだけ高くしたいものです。ビルボードは両側に2本の鋼製の支柱で支えられますが、それぞれの支柱は必ず同じ高さでなければなりません。また、溶接によって自由に接合できる棒(ロッド)のコレクションが与えられます。たとえば、長さ1、2、3のロッドがあれば、これらをつなぎ合わせて長さ6の支柱を作ることができます。ここでの課題は、ビルボードを支えられる最大の高さを求めることです。もしビルボードを支えることができない場合は0を返します。
たとえば、入力が [1,2,2,3,3,3,4] の場合、出力は9になります。これは、ロッドを [1,2,2,4](合計9)と [3,3,3](合計9)という2つのグループに分けられるためです。
解法の考え方
この問題は動的計画法(DP)を用いて解きます。ポイントとなるのは、左右の支柱の高さの差に着目することです。
dp[i][j] を「i本目までのロッドを使ったとき、左右の支柱の高さの差が j − 5000 である状態における、低い方の支柱の高さの最大値」と定義します。差は負の値にもなり得るため、オフセットとして5000を加えて配列のインデックスに対応させています。
各ロッドについては、「高い方の支柱に追加する」「低い方の支柱に追加する」「使わない」の3つの選択肢があり、これらをすべて試しながらDPテーブルを更新していきます。
アルゴリズムの手順
sum := 0、n := ロッドの数、N := 2 * 5000 とします
(n + 1) × (N + 1) のサイズを持つ2次元配列 dp を -1 で初期化します
dp[0, 5000] := 0 と設定します(差0・高さ0の初期状態)
i := 0 から i < n の間、以下を繰り返します
j := 0 から j <= N の間、以下を繰り返します
x := rods[i] とします
j − x >= 0 かつ dp[i, j − x] ≠ -1 の場合:dp[i + 1, j] = max(dp[i + 1, j], dp[i, j − x] + x)(低い方の支柱に追加)
j + x <= N かつ dp[i, j + x] ≠ -1 の場合:dp[i + 1, j] = max(dp[i + 1, j], dp[i, j + x])(高い方の支柱に追加)
dp[i, j] ≠ -1 の場合:dp[i + 1, j] = max(dp[i, j], dp[i + 1, j])(ロッドを使用しない)
最後に dp[n, 5000](差が0、つまり両支柱が等しい高さの状態)を返します
それでは、理解を深めるために以下の実装を見てみましょう。
実装例(C++)
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int tallestBillboard(vector<int>& rods){
int sum = 0;
int n = rods.size();
int N = 2 * 5000;
vector<vector<int> > dp(n + 1, vector<int>(N + 1, -1));
dp[0][5000] = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j <= N; j++) {
int x = rods[i];
if (j - x >= 0 && dp[i][j - x] != -1) {
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j - x] +
x);
}
if (j + x <= N && dp[i][j + x] != -1) {
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j + x]);
}
if (dp[i][j] != -1) {
dp[i + 1][j] = max(dp[i][j], dp[i + 1][j]);
}
}
}
return dp[n][5000];
}
};
main(){
Solution ob;
vector<int> v = {1,2,2,3,3,3,4};
cout << (ob.tallestBillboard(v));
}
入力
{1,2,2,3,3,3,4}
出力
9
-
C++で質素数(Frugal Number)を判定する方法【サンプルコード付き】
この記事では、正の整数 N が与えられたときに、その数が質素数(Frugal Number)であるかどうかを判定するプログラムを C++ で作成する方法を解説します。 質素数とは? 質素数(FRUGAL NUMBER)とは、その数自身の桁数が、素因数分解による表現の桁数よりも厳密に大きい数のことです。 例:625 の場合 625 を素因数分解すると 54 となります。 625 自身の桁数:3 桁 54 の表現の桁数:2 桁 3 は 2 よりも厳密に大きいため、625 は質素数です。 最初のいくつかの質素数:125、128、243、256、343、512、625 など 問題を理解するための具
-
C++で五胞体数(ペンタトープ数)を求める方法
五胞体数とは? 五胞体数(ペンタトープ数)は、パスカルの三角形の第5の対角線上に現れる数列として知られています。この数列を定義するには、パスカルの三角形に少なくとも5つの数が必要となるため、数列の最初の数はパスカルの三角形の第4行である 1 4 6 4 1 から始まります。 本チュートリアルでは、n番目の五胞体数を求める方法を解説します。まずは具体的な例を見てみましょう。 入力 : 1出力 : 1入力 : 4出力 : 35 以下の図から出力を確認できます。 この問題は数列に関するものなので、解法ではまず数列のパターンを見つけることから始めます。 解法のアプローチ このプログラムでは、数列の