力扣10.3

1514. 概率最大的路径

给你一个由 n 个节点(下标从 0 开始)组成的无向加权图,该图由一个描述边的列表组成,其中 edges[i] = [a, b] 表示连接节点 ab 的一条无向边,且该边遍历成功的概率为 succProb[i]

指定两个节点分别作为起点 start 和终点 end ,请你找出从起点到终点成功概率最大的路径,并返回其成功概率。

如果不存在从 startend 的路径,请 返回 0 。只要答案与标准答案的误差不超过 1e-5 ,就会被视作正确答案。

数据范围

  • 2 <= n <= 10^4
  • 0 <= start, end < n
  • start != end
  • 0 <= a, b < n
  • a != b
  • 0 <= succProb.length == edges.length <= 2*10^4
  • 0 <= succProb[i] <= 1
  • 每两个节点之间最多有一条边

分析

Dijkstra算法,只是求最长路,将初始 d i s dis dis设置为1

代码

typedef pair<double, int> PDI;
class Solution {
public:
    const static int N = 1e5 + 5;
    int head[N], e[N * 2], ne[N * 2], idx = 0;
    double dis[N];
    double w[N * 2];
    bool vis[N];
    void add(int a, int b, double c) {
        e[idx] = b;
        w[idx] = c;
        ne[idx] = head[a];
        head[a] = idx ++ ;
    }
    double djs(int n, vector<vector<int>>& edges, vector<double>& succProb, int s, int t) {
        priority_queue<PDI, vector<PDI>, less<PDI> > heap;
        heap.push({0, s});
        dis[s] = 1;
        while(heap.size()) {
            auto k = heap.top();
            heap.pop();
            int pos = k.second;
            if(vis[pos]) continue;
            vis[pos] = true;
            for(int i = head[pos]; i != -1; i = ne[i]) {
                int j = e[i];
                if(dis[j] < dis[pos] * w[i]) {
                    dis[j] =  dis[pos] * w[i];
                    heap.push({dis[j], j});
                }
            }
        }
        return dis[t];
    }
    double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int s, int t) {
        memset(head, -1, sizeof(head));
        for(int i = 0; i < edges.size(); i ++ ) {
            add(edges[i][0], edges[i][1], succProb[i]);
            add(edges[i][1], edges[i][0], succProb[i]);
        }
        return djs(n, edges, succProb, s, t);
    }
};

参考


1928. 规定时间内到达终点的最小花费

一个国家有n 个城市,城市编号为 0n - 1 ,题目保证 所有城市 都由双向道路 连接在一起 。道路由二维整数数组 edges 表示,其中 edges[i] = [xi, yi, timei] 表示城市 xiyi 之间有一条双向道路,耗费时间为 timei 分钟。两个城市之间可能会有多条耗费时间不同的道路,但是不会有道路两头连接着同一座城市。

每次经过一个城市时,你需要付通行费。通行费用一个长度为 n 且下标从 0 开始的整数数组 passingFees 表示,其中 passingFees[j] 是你经过城市j 需要支付的费用。

一开始,你在城市 0 ,你想要在maxTime 分钟以内 (包含 maxTime 分钟)到达城市 n - 1 。旅行的 费用 为你经过的所有城市 通行费之和 (包括 起点和终点城市的通行费)。

给你maxTimeedgespassingFees ,请你返回完成旅行的 最小费用 ,如果无法在 maxTime 分钟以内完成旅行,请你返回 -1

数据范围

  • 1 <= maxTime <= 1000
  • n == passingFees.length
  • 2 <= n <= 1000
  • n - 1 <= edges.length <= 1000
  • 0 <= xi, yi <= n - 1
  • 1 <= timei <= 1000
  • 1 <= passingFees[j] <= 1000
  • 图中两个节点之间可能有多条路径。
  • 图中不含有自环。

分析

d p [ i ] [ j ] dp[i][j] dp[i][j]表示恰好在 i i i时间到达 j j j的最小费用,状态转移如下

  • d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i − c ] [ f r o m ] + p a s s i n g F e e s [ j ] ) dp[i][j]=min(dp[i][j],dp[i-c][from]+passingFees[j]) dp[i][j]=min(dp[i][j],dp[ic][from]+passingFees[j])

初始状态 d p [ 0 ] [ 0 ] = p a s s i n g F e e s [ 0 ] dp[0][0]=passingFees[0] dp[0][0]=passingFees[0]
最后 r e s = M I N i = 1 m a x T i m e d p [ i ] [ n − 1 ] res=MIN_{i=1}^{maxTime}dp[i][n-1] res=MINi=1maxTimedp[i][n1]

代码

class Solution {
public:
    const static int N = 1005, INF = INT_MAX / 2;
    int dp[N][N];
    int minCost(int maxTime, vector<vector<int>>& edges, vector<int>& passingFees) {
        memset(dp, 0x3f, sizeof(dp));
        dp[0][0] = passingFees[0];
        int n =passingFees.size();
        for(int i = 0; i <= maxTime; i ++ ) {
            for(int j = 0; j < edges.size(); j ++ ) {
                int a = edges[j][0], b = edges[j][1], c = edges[j][2];
                if(c <= i) {
                    dp[i][b] = min(dp[i][b], dp[i - c][a] + passingFees[b]);
                    dp[i][a] = min(dp[i][a], dp[i - c][b] + passingFees[a]);
                }
            }
        }
        int res = INF;
        for(int i = 1; i <= maxTime; i ++ ) {
            res = min(res, dp[i][n - 1]);
        }
        if(res > INF / 2) return -1;
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值