二分探索②:解を仮定して判定(全4回)

解を仮定して判定(最大値)

二分探索 を使うと、ある条件を満たす最大値を求めるときに非常に有用です。

問題

N本の紐 があり長さはそれぞれ異なります。

これらの紐を切って、同じ長さの紐をK本 作るときの 最長の長さ を求めなさい。

答えは小数点以下2桁までを切り捨ててください。

ソースコード

区間の 下端lbを条件満たす値 に、上端ubを条件を満たさない値 にそれぞれ初期化し、解の存在範囲(lb、ub)が十分小さくなるまで、中央の値が条件を満たすかどうか判定し存在範囲を狭めていきます。

最終的に、lbが求めたい 最大の値 となります。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#------ 入力例 ------
lst = [8.12, 7.53, 4.47, 5.29] # 各紐のながさ
k = 11 # 作りたい同じ長さの紐の本数
#--------------------
n = len(lst) # 紐の本数

# 長さxの紐をk本作れるかどうか
def check(x):
cnt = sum([int(l / x) for l in lst])
return cnt >= k

lb = 0 # 初期化(下限の範囲)
ub = 999999 # 初期化(上限の範囲)

# 解の存在範囲が十分狭くなるまで繰り返す
for _ in range(99):
mid = (lb + ub) / 2
if check(mid):
lb = mid
else:
ub = mid

# 小数点第2までを切り捨て
print(('解: {:.2f}').format(lb * 100 // 100))

[実行結果]

解: 2.00

長さが2 であれば、11本の同じ長さの紐 が作れることを導き出すことができました。

解を仮定して判定(最小値)

上記の処理と同様にある条件を満たす 最小値 を求めることもできます。

区間の 下端lbを条件満たさない値 に、上端ubを条件を満たす値 にそれぞれ初期化し、解の存在範囲(lb、ub)が十分小さくなるまで、中央の値が条件を満たすかどうか判定し存在範囲を狭めていきます。

最終的に、ub が求めたい 最小の値 となります。