【搜索】A079_LC_为高尔夫比赛砍树(反向思维 bfs)

一、Problem

你被请来给一个要举办高尔夫比赛的树林砍树. 树林由一个非负的二维数组表示, 在这个数组中:

  • 0 表示障碍,无法触碰到.
  • 1 表示可以行走的地面.
  • 比 1 大的数 表示一颗允许走过的树的高度.

每一步,你都可以向上、下、左、右四个方向之一移动一个单位,如果你站的地方有一棵树,那么你可以决定是否要砍倒它。

你被要求按照树的高度从低向高砍掉所有的树,每砍过一颗树,树的高度变为 1

你将从(0,0)点开始工作,你应该返回你砍完所有树需要走的最小步数。 如果你无法砍完所有的树,返回 -1 。

可以保证的是,没有两棵树的高度是相同的,并且你至少需要砍倒一棵树。

输入: 
[
 [2,3,5],
 [0,0,4],
 [8,7,6]
]
输出: 8
解释: (0,0) 位置的树,你可以直接砍去,不用算步数

提示:

1 <= forest.length <= 50
1 <= forest[i].length <= 50
0 <= forest[i][j] <= 10^9

二、Solution

方法一:bfs

题意

砍完一个点 (i, j) 的树,寻找下一棵比当前树高度小的树 next,注,关键来了:① next 可能不在 (i, j) 的周围(上下左右),也就是说,你可以砍完树回去再回来也是可以的 🤦‍♂️

所以,这题不能裸着做

思路

将树的位置、树高先预处理到一个容器中;然后容器按照树高进行排序;最后就是检查初始位置 (0, 0) 能否到达树的每一个位置,到不了就不能砍完树

这样我们就只需要计算所有 “相邻” 的树的距离总和

class Solution {
public:
    struct node {int x, y;};
    int n, m, d[4][2] = { {1,0},{0,-1},{0,1},{-1,0} };
    int cutOffTree(vector<vector<int>>& g) {
        n=g.size(), m=g[0].size();
        vector<vector<int>> ts;

        for (int i=0; i<n; i++)
        for (int j=0; j<m; j++) if(g[i][j]) {
            ts.push_back({i, j, g[i][j]});
        }
        sort(ts.begin(), ts.end(), [&] (auto t1, auto t2){
            return t1[2] < t2[2]; 
        });
        int sx=0, sy=0, ans=0;
        for (auto& t : ts) {
            int dist = bfs(sx, sy, t[0], t[1], g);
            if (dist == -1) return -1;
            sx=t[0], sy=t[1], ans += dist;
        }
        return ans;
    }
    int bfs(int sx, int sy, int ex, int ey, vector<vector<int>>& g) {
        int op=0, vis[n][m];
        queue<node> q;
        memset(vis, 0, sizeof vis);
        q.push({sx, sy}), vis[sx][sy]=1;

         while (!q.empty()) {
            for (int i=q.size(); i; i--) {
                node now = q.front(); q.pop();
                if (now.x==ex && now.y==ey) return op;
                for (int k=0; k<4; k++) {
                    int xx=now.x+d[k][0], yy=now.y+d[k][1];
                    if (xx>=0 && xx<n && yy>=0 && yy<m && !vis[xx][yy] && g[xx][yy]) {
                        q.push({xx, yy});
                        vis[xx][yy]=1;
                    }
                }
            }
            op++;
        }
        return -1;
    }
};

复杂度分析

  • 时间复杂度: O ( Q × n m ) O(Q × nm) O(Q×nm),792 ms…
  • 空间复杂度: O ( n m ) O(nm) O(nm)

方法二:


复杂度分析

  • 时间复杂度: O ( ) O() O()
  • 空间复杂度: O ( ) O() O()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值