Pythonで新鮮なドーナツを受け取れるグループの最大数を求めるプログラム
問題の概要
整数 batchSize(バッチサイズ)と配列 groups が与えられます。groups[i] は、i 番目のグループに groups[i] 人の顧客がいることを意味します。あるドーナツ店では、指定された batchSize 個ずつドーナツを焼いており、「前のバッチのドーナツをすべて提供し終えるまで、次のバッチのドーナツを提供してはならない」というルールがあります。各顧客は必ずドーナツを1個受け取り、あるグループが来店した場合は、そのグループ全員の対応が終わるまで次のグループには対応できません。
グループの全員が新鮮なドーナツを受け取れたとき、そのグループは「幸せ(happy)」とみなされます。言い換えれば、グループの先頭の顧客が、直前のグループで余ったドーナツを受け取ってしまった場合、そのグループは幸せではありません。
グループの順番は自由に入れ替えられるものとし、入れ替え後に幸せになれるグループ数の最大値を求めます。
入力例
batchSize = 4、groups = [2,1,8,4,3] の場合、出力は 4 になります。グループを [8,4,2,3,1] の順に並べ替えると、1番目・2番目・3番目・4番目のグループが幸せになります。具体的には、1番目のグループ用に2バッチ、2番目のグループ用に1バッチを焼き、その後1バッチ焼いて3番目のグループへ、さらに1バッチ焼いて4番目のグループへ提供します。
アプローチ
この問題を解くには、以下の手順に従います。
l:groupsの各要素gをbatchSizeで割った余り(g % batchSize)のリストを作成するcount:lの各要素の出現回数を記録したマップを作成するg: 余り 0 〜 batchSize-1 それぞれの個数(count[i])のリストを作成する- 関数
dp(sm, t)を定義する(smは現在の累積余り、tは残っている各余りクラスのグループ数) tの最大値が 0 の場合(すべてのグループを処理済み)、0 を返すans = 0、arr = tとして初期化する- k を 0 〜 batchSize-1 までループする:
arr[k]が 0 なら次の反復へスキップするarr[k]を 1 減らすans = max(ans, dp((sm + k) % batchSize, arr))で再帰的に探索するarr[k]を元に戻す(バックトラック)
smが 0 の場合はans + 1、そうでなければansを返す- メイン処理では
dp(0, g)の結果を返す
考え方のポイント
重要なのは、グループの人数そのものではなく「batchSize で割った余り」だけが結果に影響するという点です。バッチの境界でドーナツが余るかどうかは、それまでの累積人数を batchSize で割った余りだけで決まるためです。dp 関数は、次にどの余りクラスのグループを並べるかを全通り試しながら探索を行い、新しいグループの開始時点で累積和が 0(= バッチの境目と一致)であれば、そのグループは新鮮なドーナツを受け取れるとして答えに 1 を加算します。
なお、この実装はすべての並べ方を試すため、グループ数が多いほど計算量が増大します。競技プログラミング(LeetCode 1815 など)では batchSize ≤ 9 という制約のもとで、functools.lru_cache などによるメモ化を併用すると、同じ状態の再計算を避けて効率よく解くことができます。
実装例(Python)
以下の実装を見ると、理解がより深まります。
from collections import Counter
def solve(batchSize, groups):
l = [g % batchSize for g in groups]
count = Counter(l)
g = [count[i] for i in range(batchSize)]
def dp(sm, t):
if max(t) == 0:
return 0
ans, arr = 0, list(t)
for k in range(batchSize):
if arr[k] == 0:
continue
arr[k] -= 1
ans = max(ans, dp((sm + k) % batchSize, arr))
arr[k] += 1
return ans + (sm == 0)
return dp(0, g)
batchSize = 4
groups = [2, 1, 8, 4, 3]
print(solve(batchSize, groups))
入力
4, [2,1,8,4,3]
出力
4
-
Pythonでリスト内の最大値を見つける方法|sort()とmax()の2つのアプローチ
この記事では、リストの中から最大の数値を見つけるための解決策とアプローチについて詳しく解説します。問題の概要数値のリストが与えられたとき、その中から最大の要素を見つけ出す必要があります。Pythonでは、主に以下の2つの方法でこれを実現できます。ソート(並べ替え)を利用する方法組み込み関数 max() を利用する方法アプローチ1:sort() 関数を使う方法リストを sort() メソッドで昇順に並べ替えると、リストの最後の要素(インデックス -1)が必ず最大値になります。サンプルコードlist1 = [18, 65, 78, 89, 90] list1.sort() # メイン処理 prin
-
【Python入門】3つの数値から最大値を求める方法
3つの数値 a、b、c が与えられたとき、その中で最も大きい要素(最大値)を見つけるのが今回の課題です。ここでは、Pythonのリストと組み込み関数 max() を使ったシンプルな方法を、初心者向けにわかりやすく解説します。 実行例 入力:a = 2, b = 4, c = 3 出力:4 アルゴリズム ステップ1:ユーザーから3つの数値を入力として受け取る。 ステップ2:3つの数値をリストに格納する。 ステップ3:max() 関数を使ってリスト内の最大値 max(lst) を求める。 ステップ4:最後に最大値を出力する。 サンプルコード def maximum(a, b, c):