最小値の最大化(二分探索)と、反転操作回数の最小化
面白い問題があったのでPythonで記載。
問題 1
N個の牛小屋について、M頭の牛を買っている。 x・・・牛小屋の位置 最も近い牛の間隔を最大化するためにどうするか
解法
最小・最大化問題について、収束判定するために二分探索が用いられるらしい --> 総当たり的な感じ
class IntervalOptimize(object): def __init__(self, N, M, x_): self.N = N self.M = M self.x_ = sorted(x_) self._max = max(self.x_) def assetion(self, d): last = 0 for i in range(self.M): crt = last + 1 while (crt < self.N) and (self.x_[crt] - self.x_[last] < d): crt += 1 if crt > self.N: return False last = crt return True def solve(self): lb, ub = 0, self._max while ub - lb > 1: mid = (ub + lb) // 2 if self.assetion(mid): lb = mid else: ub = mid return lb
In [114]: i = IntervalOptimize(5, 3, [1,2,8,4,9]) In [115]: i.solve() Out[115]: 3
問題 2
N頭に並んでいる牛が前か後ろ向いている(1: 前、2: 後ろ)。 連続するK頭ずつ反転させることができる。 最小の操作回数Mと、それを達成するための最小のKを求めよ。
解法
反転する順番は順不同なため、はじめから順に反転させる。あとは、貪欲に。。
class CowReverse(object): def __init__(self, N, direction_): self.N = N self.direction_ = direction_ def calc(self, k): f = [0 for i in range(self.N)] res = 0 _sum = 0 for i in range(self.N - k + 1): if (self.direction_[i] + _sum) % 2 != 0: res += 1 f[i] = 1 _sum += f[i] if i - k + 1 >= 0: _sum -= f[i - k + 1] for i in range(self.N - k + 1, self.N): if (self.direction_[i] + _sum) % 2 != 0: return -1 _sum += f[i] if i - k + 1 >= 0: _sum -= f[i - k + 1] return res def solve(self): K = 1 M = self.N for k in range(1, self.N + 1): m = self.calc(k) if m >= 0 and M > m: K = k M = m return '{:d} {:d}'.format(K, M)
In [126]: direction_list = '1101011' In [134]: c = CowReverse(len(direction_list), [int(i) for i in list(direction_list)]) In [135]: c.solve() Out[135]: '3 3'