Skip to content

Commit 2b59032

Browse files
committed
675
1 parent e4c7c88 commit 2b59032

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

General/675.md

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
## 675 Cut Off Trees for Golf Event
2+
3+
#### Description
4+
5+
[link](https://leetcode.com/problems/cut-off-trees-for-golf-event/)
6+
7+
---
8+
9+
#### General Type
10+
11+
[A* 寻路算法](https://www.cnblogs.com/wangnfhy/p/4956711.html)
12+
13+
---
14+
15+
#### General Solution
16+
17+
A* 算法的本质是用来寻路,上面那篇blog讲的非常详细,简单总结
18+
19+
发展历程:BFS -> Dijkstra -> Greedy BFS -> A*
20+
21+
Core:
22+
23+
- 使用两个list,其中openlist是当前需要遍历的节点,而closelist是已经遍历完成的节点
24+
- openlist在不同情况下是不同优先队列,以F(N)为优先级
25+
- F(N)=G(N)+H(N)
26+
- G(N)就是从起点到当前节点N的移动消耗
27+
- H(N),在只允许上下左右移动的前提下,就是最好优先贪婪算法中当前节点N到目标节点E的曼哈顿距离
28+
29+
算法流程:
30+
31+
1. 选择起始节点S和目标节点E,将(S,0)(节点,节点F(N)值)放入openList,openList是一个优先队列,节点F(N)值越小,优先级越高。
32+
2. 判断openList是否为空,若为空,则搜索失败,目标节点不可达;否则,取出openList中优先级最高的节点P;
33+
3. 遍历P的上下左右四个相邻接点N1-N4,对每个节点N,如果N已经在closeList中,忽略;否则有两种情况,
34+
1. 如果N不在openList中,令GN=GP+DPN,计算N到E的曼哈顿距离HN,令FN=GN+HN,令N的父节点为P,将(N,FN)放入openList;
35+
2. 如果N已经在openList中,计算GN1= GP+DPN,如果GN1小于GN,那么用新的GN1替换GN,重新计算FN,用新的(N,FN)替换openList中旧的(N,FN),令N的父节点为P;如果GN1不小于GN,不作处理。
36+
4. 将节点P放入closeList中。判断节点P是不是目标节点E,如果是,搜索成功,获取节点P的父节点,并递归这一过程(继续获得父节点的父节点),直至找到初始节点S,从而获得从P到S的一条路径;否则,重复步骤2;
37+
38+
#### Solution
39+
40+
- [Explanation](https://leetcode.com/problems/cut-off-trees-for-golf-event/discuss/107396/Python-solution-based-on-wufangjie's-(Hadlock's-algorithm))
41+
42+
Distance() 求解Tree到下一个Tree的距离,如果使用BFS会浪费大量时间在全图扫描上,所以这里使用一种取巧的办法
43+
44+
- 首先判断是否所有的tree都可以遍历到,不能的话返回-1
45+
- 当前now数组保存所有靠近目标的节点,closer
46+
- soon数组保存所有需要绕路的节点
47+
- 每当now遍历完而没有达到目标时,替换soon为now,此时因为soon当中都是多绕了一次路的,所以计算结果需要加上2
48+
49+
***为什么可以节约时间在于每次先从最优解开始求起而不是遍历全图,就算是存在绕路也接近最优解***
50+
51+
---
52+
53+
#### Code
54+
55+
```python
56+
class Solution:
57+
def cutOffTree(self, forest: List[List[int]]) -> int:
58+
# Add sentinels (a border of zeros) so we don't need index-checks later on.
59+
forest.append([0] * len(forest[0]))
60+
for row in forest:
61+
row.append(0)
62+
63+
# Find the trees.
64+
trees = [(height, i, j)
65+
for i, row in enumerate(forest)
66+
for j, height in enumerate(row)
67+
if height > 1]
68+
69+
# Can we reach every tree? If not, return -1 right away.
70+
queue = [(0, 0)]
71+
reached = set()
72+
for i, j in queue:
73+
if (i, j) not in reached and forest[i][j]:
74+
reached.add((i, j))
75+
queue += (i+1, j), (i-1, j), (i, j+1), (i, j-1)
76+
if not all((i, j) in reached for (_, i, j) in trees):
77+
return -1
78+
79+
# Distance from (i, j) to (I, J).
80+
def distance(i, j, I, J):
81+
now, soon = [(i, j)], []
82+
expanded = set()
83+
manhattan = abs(i - I) + abs(j - J)
84+
detours = 0
85+
while True:
86+
if not now:
87+
now, soon = soon, []
88+
detours += 1
89+
i, j = now.pop()
90+
if (i, j) == (I, J):
91+
return manhattan + 2 * detours
92+
if (i, j) not in expanded:
93+
expanded.add((i, j))
94+
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):
95+
if forest[i][j]:
96+
(now if closer else soon).append((i, j))
97+
98+
# Sum the distances from one tree to the next (sorted by height).
99+
trees.sort()
100+
return sum(distance(i, j, I, J) for (_, i, j), (_, I, J) in zip([(0, 0, 0)] + trees, trees))
101+
```

0 commit comments

Comments
 (0)