【Leetcode】2812. Find the Safest Path in a Grid

题目地址:

https://leetcode.com/problems/find-the-safest-path-in-a-grid/description/

给定一个 n × n n\times n n×n 01 01 01矩阵, 1 1 1代表贼, 0 0 0代表空地,每个位置的安全系数为其和与其曼哈顿距离最近的贼的曼哈顿距离。现在要从 ( 0 , 0 ) (0,0) (0,0)走到 ( n − 1 , n − 1 ) (n-1,n-1) (n1,n1),每一步只能走 4 4 4个方向,不能出界。一条路径的安全系数定义为其包含的所有点的安全系数的最小值。问安全系数最大的路径的安全系数。

思路是多源BFS+最小生成树Kruskal算法。先用多源BFS求出每个位置的安全系数,然后再用Kruskal算法。设安全系数矩阵为 c c c,那么问题就变为在 c c c里的所有从左上到右下的路径中,路径上最小值最大的那条路径的路径点最小值。可以将相邻点连边,那么经过这条边的安全系数就是两个点的安全系数的较小值。我们可以按安全系数从高到低对所有边排序,然后依次将边加上去(按照Kruskal算法的步骤),一旦加了某条边能使得左上和右下连通,那么这条边的安全系数就是答案。代码如下:

class Solution {
 public:
  using PII = pair<int, int>;
  struct Edge {
    int x, y, w;
  };
  vector<int> p;
  int maximumSafenessFactor(vector<vector<int>>& g) {
    int n = g.size(), nn = n * n;
    p.resize(nn);
    for (int i = 0; i < nn; i++) p[i] = i;
    queue<PII> q;
    vector<vector<int>> s(n, vector<int>(n, -1));
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (g[i][j]) {
          q.push({i, j});
          s[i][j] = 0;
        }
    static int d[] = {-1, 0, 1, 0, -1};
    while (q.size()) {
      auto t = q.front();
      q.pop();
      int x = t.first, y = t.second;
      for (int k = 0; k < 4; k++) {
        int nx = x + d[k], ny = y + d[k + 1];
        if (0 <= nx && nx < n && 0 <= ny && ny < n) {
          if (~s[nx][ny]) continue;
          s[nx][ny] = s[x][y] + 1;
          q.push({nx, ny});
        }
      }
    }

    auto f = [&](int x, int y) { return x * n + y; };
    vector<Edge> es;
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++) {
        if (i + 1 < n)
          es.push_back({f(i, j), f(i + 1, j), min(s[i][j], s[i + 1][j])});
        if (j + 1 < n)
          es.push_back({f(i, j), f(i, j + 1), min(s[i][j], s[i][j + 1])});
      }

    sort(es.begin(), es.end(), [&](auto& e1, auto& e2) { return e1.w > e2.w; });

    auto merge = [&](int x, int y) {
      int px = find(x), py = find(y);
      p[px] = py;
    };
    for (auto& e : es) {
      int x = e.x, y = e.y, w = e.w;
      merge(x, y);
      if (find(0) == find(nn - 1)) return w;
    }

    return 0;
  }

  int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
};

时间复杂度 O ( n 2 log ⁡ n ) O(n^2\log n) O(n2logn),空间 O ( n 2 ) O(n^2) O(n2)

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值