【Leetcode】2093. Minimum Cost to Reach City With Discounts

题目地址:

https://leetcode.com/problems/minimum-cost-to-reach-city-with-discounts/description/

给定一个 n n n个顶点 m m m条边的带权无向图,顶点编号 0 ∼ n − 1 0\sim n-1 0n1。要从 0 0 0走到 n − 1 n-1 n1,再给定 d d d次机会,每次走一条边的时候可以使用 1 1 1次机会使得边权以原来的一半走过。问最短路长度。

分层图最短路问题,将 ( u , g ) (u, g) (u,g)看成一个整体, u u u为顶点, g g g为还剩多少次“半价”的机会。那么问题转为在新图上的最短路问题,可以用Dijkstra算法来做。代码如下:

class Solution {
 public:
#define x first
#define y second
  using PII = pair<int, int>;
  vector<int> h, e, ne, w;
  int idx;
#define add(a, b, c) e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++

  int minimumCost(int n, vector<vector<int>> &es, int d) {
    int m = es.size() * 2;
    h.resize(n, -1);
    e.resize(m);
    ne.resize(m);
    w.resize(m);
    idx = 0;

    for (auto &ed : es) add(ed[0], ed[1], ed[2]), add(ed[1], ed[0], ed[2]);

    int dist[n][d + 1];
    memset(dist, 0x3f, sizeof dist);
    dist[0][d] = 0;
    auto cmp = [&](const PII &p1, const PII &p2) {
      return dist[p1.x][p1.y] > dist[p2.x][p2.y];
    };
    priority_queue<PII, vector<PII>, decltype(cmp)> heap(cmp);
    heap.push({0, d});
    bool vis[n][d + 1];
    memset(vis, 0, sizeof vis);
    while (heap.size()) {
      auto t = heap.top();
      heap.pop();
      int u = t.x, d = t.y;
      if (u == n - 1) return dist[u][d];
      if (vis[u][d]) continue;
      vis[u][d] = true;
      for (int i = h[u]; ~i; i = ne[i]) {
        int v = e[i];
        if (!vis[v][d] && dist[v][d] > dist[u][d] + w[i]) {
          dist[v][d] = dist[u][d] + w[i];
          heap.push({v, d});
        }
        if (d && !vis[v][d - 1] && dist[v][d - 1] > dist[u][d] + w[i] / 2) {
          dist[v][d - 1] = dist[u][d] + w[i] / 2;
          heap.push({v, d - 1});
        }
      }
    }

    return -1;
  }
};

时间复杂度 O ( n d log ⁡ ( n d m ) ) O(nd\log (ndm)) O(ndlog(ndm)),空间 O ( n d ) O(nd) O(nd)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值