Python currently fastest implementation 610ms (same method as @wufangjie's, perf improved)
Disclaimer: * This solution is inspired by @wufangjie's solution (as I summarized below) * My contribution is to improve the performance to 610ms (currently fas
Disclaimer:
* This solution is inspired by @wufangjie's solution (as I summarized below)
* My contribution is to improve the performance to 610ms (currently fastest among all python submissions, with the second fastest be around 700ms)

Summary of the solution:

1. first floodfill to make sure all trees are reachable for each pair of trees (pairs defined in step 3)
2. sort distances between all trees, call routine 3 to calculate minimum distance between pairs of trees (with closest height) and return the sum.
3. calculate the minimum distance between a pair of trees as following:
3.1. bfs through only the paths which can achieve theoretical minimum distance (i.e. `cost`) between the two points
3.2. while doing the above bfs, keep a note of the seed nodes which can achieve `cost + 2` distance
3.3. if 3.1 failed, switch to the next level, which is to bfs from the seed nodes found in 2.2 with `cost += 2`
3.4. keep the above loop 3.1 ~ 3.3, until there are no more seed nodes for the next level

This implementation appears to be faster than @wufangjie's and is currently the fastest (i.e. beats 100% of the python solutions as of 2/18/2018). I submitted it three times to confirm that it's the fastest, got: 644 ms, 608 ms, 612 ms, with the second fastest running time from other submissions to be 700ms.

The first part of the implemention is similar to @wufangjie's, while the last part (i.e. shortest distance between tree pairs) differs in some details. Two major differences:

* The judgement of whether a movement will cost additional 2 steps is unified without many `if` statements.
* New neighbors are directly added into existing queues without creating temporary lists.

Side note:
* The usage of `list`s with `append()` and `pop()` for `queue` and `next_queue` are important (as also did in @wufangjie's implementation). Changing them to `deque`s with `append()` and `popleft()` will slow down the perf about three times.

```
class Solution:
    d = [(1, 0), (-1, 0), (0, 1), (0, -1)]

    def cutOffTree(self, forest):
        #print(forest)
        rows = len(forest)
        if rows == 0:
            return 0

        cols = len(forest[0])
        if cols == 0:
            return 0

        forest.append([0] * cols)
        for row in forest:
            row.append(0)

        trees = {(r, c) for c in range(cols) for r in range(rows) if forest[r][c] > 1}

        visited = {(0, 0)}
        queue = [(0, 0)]
        while len(queue) != 0:
            r, c = queue.pop()
            for nr, nc in ((r + dr, c + dc) for dr, dc in self.d):
                if (nr, nc) not in visited and forest[nr][nc] > 0:
                    visited.add((nr, nc))
                    queue.append((nr, nc))

        if trees.difference(visited):
            return -1

        trees = sorted(trees, key=lambda t: forest[t[0]][t[1]])
        if trees[0] != (0, 0):
            trees.insert(0, (0, 0))
        num_trees = len(trees)
        #print('TREES:', trees)

        total_steps = 0
        for i in range(1, num_trees):
            pr, pc = p = trees[i - 1]
            qr, qc = q = trees[i]
            cost = abs(pr - qr) + abs(pc - qc)

            queue, next_queue = [], [] # Using list: 0.53s, 0.52s, 0.54s
            #queue, next_queue = deque(), deque() # Using deque: 1.45s, 1.50s, 1.46s
            queue.append(p)
            visited, pending_visited = {p}, set()
            while len(queue) + len(next_queue) != 0:
                if len(queue) == 0:
                    queue = next_queue
                    next_queue = deque()

                    visited.update(pending_visited)
                    pending_visited = set()
                    cost += 2

                (r, c) = queue.pop() # Using list
                #(r, c) = queue.popleft() # Using deque
                #print('POP', r, c, cost)

                safe_dr = qr - r
                safe_dr = safe_dr and safe_dr // abs(safe_dr)
                safe_dc = qc - c
                safe_dc = safe_dc and safe_dc // abs(safe_dc)
                for dr, dc in self.d:
                    nbr = (r + dr, c + dc)
                    if nbr not in visited and forest[nbr[0]][nbr[1]] > 0:
                        #print('SAFE', (safe_dr, safe_dc), 'D', (dr, dc))
                        if (dr == safe_dr and dc != -safe_dc) or (dc == safe_dc and dr != -safe_dr):
                            queue.append(nbr)
                            visited.add(nbr)
                            ncost = cost
                            #print('PUSH', nbr)
                        else:
                            next_queue.append(nbr)
                            pending_visited.add(nbr)
                            ncost = cost + 2
                            #print('PUSH NEXT', nbr)
                        if nbr == q:
                            #print('COST:', p, q, ncost)
                            total_steps += ncost
                            queue = next_queue = list()
                            break

                # print('MAP', cost)
                # for rr in range(rows):
                #     for cc in range(cols):
                #         if (rr, cc) == (r, c):
                #             print('*', end='')
                #         elif (rr, cc) in queue:
                #             print('Q', end='')
                #         elif (rr, cc) in visited:
                #             print('+', end='')
                #         elif (rr, cc) in next_queue:
                #             print('N', end='')
                #         else:
                #             print(forest[rr][cc], end='')
                #     print()

        return total_steps
```
[]