C++で全ての本を購入するための最小コストを求める方法
問題の概要
n個の要素からなる配列があるとします。各要素は本の評価(レーティング)を表しています。以下の条件を満たすように、すべての本を購入する際の最小コストを求めます。
- 各本のコストは最低でも1ドル以上でなければならない
- ある本の評価が隣接する本(左または右)の評価より高い場合、その本のコストは隣の本よりも高く設定しなければならない
例えば、評価の配列が [1, 3, 4, 3, 7, 1] の場合、出力は 10 になります。これは 1 + 2 + 3 + 1 + 2 + 1 = 10 となるためです。
解法の考え方
この問題を効率的に解くには、LtoR と RtoL という2つの補助配列を用意し、すべての要素を1で初期化します。その後、次の手順で処理を進めます。
- 配列を左から右へ走査して LtoR を埋めます。直前の要素の評価と比較して値を更新しますが、次の要素の評価は考慮しません。
- 配列を右から左へ走査して RtoL を埋めます。こちらも直前(右隣)の要素の評価と比較して更新し、それ以外は考慮しません。
- 最後に、各位置 i における LtoR[i] と RtoL[i] の最大値を求め、それを結果に加算していきます。
この方法により、左右両方向の制約を同時に満たす最小のコストの組み合わせを構成できます。
C++での実装例
#include<iostream>
using namespace std;
int getMinCost(int ratings[], int n) {
int res = 0;
int LtoR[n];
int RtoL[n];
for(int i = 0; i < n; i++){
LtoR[i] = RtoL[i] = 1;
}
for (int i = 1; i < n; i++)
if (ratings[i] > ratings[i - 1])
LtoR[i] = LtoR[i - 1] + 1;
for (int i = n - 2; i >= 0; i--)
if (ratings[i] > ratings[i + 1])
RtoL[i] = RtoL[i + 1] + 1;
for (int i = 0; i < n; i++)
res += max(LtoR[i], RtoL[i]);
return res;
}
int main() {
int ratings[] = { 1, 6, 8, 3, 4, 1, 5, 7 };
int n = sizeof(ratings) / sizeof(ratings[0]);
cout << "Minimum cost is: " << getMinCost(ratings, n);
}出力結果
Minimum cost is: 15
動作の確認
入力配列 {1, 6, 8, 3, 4, 1, 5, 7} の場合、各配列は次のようになります。
- LtoR = [1, 2, 3, 1, 2, 1, 2, 3]
- RtoL = [1, 1, 2, 1, 2, 1, 1, 1]
各位置における最大値を合計すると、1 + 2 + 3 + 1 + 2 + 1 + 2 + 3 = 15 となり、これが最小コストとなります。
計算量
- 時間計算量:O(n) — 配列を3回走査するだけで済みます
- 空間計算量:O(n) — 2つの補助配列が必要です
-
C++で木の中のすべてのリンゴを収集するための最小時間を求める
問題概要 n個の頂点からなる無向木を考えます。頂点には0からn-1までの番号が付けられており、いくつかの頂点にはリンゴが置かれています。木の1つの辺を移動するのに1秒かかるとき、頂点0から出発してすべてのリンゴを集め、再び頂点0に戻るまでに必要な最小時間(秒)を求めてください。 無向木の辺は配列 edges として与えられ、edges[i] = [from_i, to_i] は頂点 from_i と頂点 to_i を結ぶ辺が存在することを表します。さらに、hasApple というブール値の配列も与えられ、hasApple[i] = true の場合は頂点 i にリンゴが存在し、false の
-
C++でフローネットワークの最小s-tカットを求める方法
最小s-tカットとは フローネットワークが与えられたとき、s-tカットとは、始点(ソース)ノード s と終点(シンク)ノード t が必ず異なる部分集合に振り分けられるような頂点の分割を指します。カットには、ソース側の集合からシンク側の集合へ向かう辺が含まれ、その容量はカット集合に含まれる各辺の容量の総和で表されます。 この記事では、与えられたネットワークの中から容量が最小となるs-tカット(最小カット)を見つけ、それを構成するすべての辺を出力する方法を解説します。 たとえば、次のようなネットワークが入力されたとします。 このときの出力は [(1,3), (4,3), (4,5)] となりま