Pythonですべての映画を上映するために必要な映画館の最小数を求めるプログラム
複数の映画の上映時間を表す区間のリストが与えられます(区間同士は重なる場合があります)。このとき、すべての映画を上映するために最低限必要な映画館の数を求める問題を考えてみましょう。
例えば、入力が intervals = [[20, 65], [0, 40], [50, 140]] の場合、出力は 2 になります。これは、[20, 65] と [0, 40] が重なっており、[20, 65] と [50, 140] も重なっていますが、[0, 40] と [50, 140] は重なっていないためです。つまり、同時に上映されている映画の最大本数が2本なので、2つのスクリーン(映画館)があれば十分だということです。
解決のアプローチ
この問題は、イベントソートと累積和を組み合わせたテクニック(いもす法として知られる手法)を使うと効率的に解けます。考え方はシンプルで、各区間の開始時刻でカウントを+1、終了時刻で-1します。その後、時刻順に並べ替えてカウントの累積値を追跡することで、各時点で同時に上映されている映画の本数がわかり、その最大値が求める答えになります。
アルゴリズムの手順
- 新しいリスト t を作成します。
- intervals 内の各区間 [a, b] について、次の処理を行います。
- t の末尾に (a, 1)(開始イベント)を追加します。
- t の末尾に (b, -1)(終了イベント)を追加します。
- ans = 0、count = 0 で初期化します。
- ソート後の t 内の各ペア (x, d) について、次の処理を行います。
- count に d を加算します。
- ans を ans と count の最大値で更新します。
- 最後に ans を返します。
実装コード
それでは、実際のPythonコードを見てみましょう。
class Solution:
def solve(self, intervals):
t = []
for a, b in intervals:
t.append((a, 1))
t.append((b, -1))
ans = count = 0
for x, d in sorted(t):
count += d
ans = max(ans, count)
return ans
ob = Solution()
intervals = [[20, 65], [0, 40], [50, 140]]
print(ob.solve(intervals))
入力
[[20, 65], [0, 40], [50, 140]]
出力
2
補足ポイント
- 計算量: 区間の数を n とすると、イベントのソートが支配的になるため、時間計算量は O(n log n)、空間計算量は O(n) となります。
- 境界の扱い: Pythonのタプル比較により、同じ時刻では (時刻, -1) の終了イベントが (時刻, 1) の開始イベントより先に処理されます。そのため、「ある映画の終了時刻 = 別の映画の開始時刻」の場合は重複とみなされず、同じスクリーンを再利用できる扱いになります。
- 応用範囲: この手法は会議室の割り当てやタスクスケジューリングなど、「区間の最大同時重複数」を求めるあらゆる問題に応用できます。
-
Pythonで全ての点を接続するための最小コストを求めるプログラム
問題の概要(x, y) の形式で表される複数の点が格納された配列 points があるとします。2つの点 (xi, yi) と (xj, yj) を接続するコストは、それらの間のマンハッタン距離として定義されます。マンハッタン距離は次の式で計算できます。|xi − xj| + |yi − yj|この問題では、すべての点を接続するために必要な最小のコストを求める必要があります。入力例points = [(0,0), (3,3), (2,10), (6,3), (8,0)]この場合、出力は 22 になります。これは、各辺の距離がそれぞれ 6 + 5 + 3 + 8 = 22 となるように点同士を接
-
Pythonで全ノードに到達可能な最小の頂点集合を見つけるプログラム
問題概要有向非巡回グラフ(DAG)を考えます。グラフにはn個の頂点があり、各ノードには0からn-1までの番号が付けられています。グラフはエッジリストとして表現され、edges[i] = (u, v)はノードuからノードvへ向かう有向エッジを意味します。このとき、そこから出発すればグラフ内のすべてのノードに到達できるような、最小の頂点集合を見つける必要があります(頂点は任意の順序で返して構いません)。例えば、入力が次のような場合を考えてみましょう。この場合、出力は [0, 2, 3] となります。これらの頂点は他のどの頂点からも到達できないため、ここから探索を開始すれば全ノードをカバーできるから