凸包
凸包構築
def dot(a, b):
return (a.conjugate() * b).real
def cross(a, b):
return (a.conjugate() * b).imag
def ccw(a, b, c):
b -= a
c -= a
cbc = cross(b, c)
if cbc > 0:
return 1
if cbc < 0:
return -1
if dot(b, c) < 0:
return 2
if abs(b) < abs(c):
return -2
return 0
def convex_hull(n, ps):
ps.sort(key=lambda p: (p.real, p.imag))
hull = [0j] * (2 * n)
i = 0
k = 0
while i < n:
while k >= 2 and ccw(hull[k - 2], hull[k - 1], ps[i]) <= 0:
k -= 1
hull[k] = ps[i]
i += 1
k += 1
i = n - 2
t = k + 1
while i >= 0:
while k >= t and ccw(hull[k - 2], hull[k - 1], ps[i]) <= 0:
k -= 1
hull[k] = ps[i]
i -= 1
k += 1
return hull[:k - 1]
凸包の直径(最遠点対)
凸包を構築し、点は時計回りに並んでいるという前提。
def convex_diameter(n, ps):
iis, ijs = 0, 0
for i in range(1, n):
if ps[i].imag > ps[iis].imag:
iis = i
if ps[i].imag < ps[ijs].imag:
ijs = i
max_d = abs(ps[iis] - ps[ijs])
i = max_i = iis
j = max_j = ijs
def diff(i):
return ps[(i + 1) % n] - ps[i]
def check(i, j):
nonlocal max_d, max_i, max_j
if cross(diff(i), diff(j)) >= 0:
j = (j + 1) % n
else:
i = (i + 1) % n
curr = abs(ps[i] - ps[j])
if curr > max_d:
max_d = curr
max_i = i
max_j = j
return i, j
i, j = check(i, j)
while i != iis or j != ijs:
i, j = check(i, j)
return max_d

