675. Cut Off Trees for Golf Event


class Solution(object):
def cutOffTree(self, forest):
# add border 0 so we do not need to index-checks later on
forest.append([0] * len(forest[0]))
for row in forest:
row.append(0)
# find the trees:
trees = [(height, i, j) for i, row in enumerate(forest)
for j, height in enumerate(row) if height > 1]
# Can we reach all the trees? if not return -1 right away
queue = [(0, 0)]
reached = set() # all the i,j can be reached
for i, j in queue:
if i >= 0 and j >= 0 and (i,j) not in reached and forest[i][j]:
reached.add((i, j))
queue += (i+1, j), (i-1, j), (i, j+1), (i, j-1)
if not all((i,j) in reached for (_, i, j) in trees):
return -1
# Distance from (i, j) to (I, J).
def distance(i, j, I, J):
now, soon = [(i, j)], []
expended = set() # 已经走过的
manhatten = abs(i-I) + abs(j-J)
detours = 0
while True:
if not now:
now, soon = soon, []
detours += 1
i, j = now.pop()
if (i, j) == (I, J):
return manhatten + 2*detours
if (i, j) not in expended:
expended.add((i, j))
for i, j, closer in ((i+1, j, i < I), (i-1, j, i > I), (i, j+1, j<J), (i, j-1, j>J)):
if forest[i][j]:
(now if closer else soon).append((i, j))
trees.sort()
return sum(distance(i, j, I, J) for (_, i, j), (_, I, J) in zip([(0, 0, 0)] + trees, trees))