1514. 概率最大的路径
给你一个由 n
个节点(下标从 0
开始)组成的无向加权图,该图由一个描述边的列表组成,其中 edges[i] = [a, b]
表示连接节点 a
和 b
的一条无向边,且该边遍历成功的概率为 succProb[i]
。
指定两个节点分别作为起点 start
和终点 end
,请你找出从起点到终点成功概率最大的路径,并返回其成功概率。
如果不存在从 start
到 end
的路径,请 返回 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
个城市,城市编号为 0
到 n - 1
,题目保证 所有城市 都由双向道路 连接在一起 。道路由二维整数数组 edges
表示,其中 edges[i] = [xi, yi, timei]
表示城市 xi
和 yi
之间有一条双向道路,耗费时间为 timei
分钟。两个城市之间可能会有多条耗费时间不同的道路,但是不会有道路两头连接着同一座城市。
每次经过一个城市时,你需要付通行费。通行费用一个长度为 n
且下标从 0
开始的整数数组 passingFees
表示,其中 passingFees[j]
是你经过城市j
需要支付的费用。
一开始,你在城市 0
,你想要在maxTime
分钟以内 (包含 maxTime
分钟)到达城市 n - 1
。旅行的 费用 为你经过的所有城市 通行费之和 (包括 起点和终点城市的通行费)。
给你maxTime
,edges
和 passingFees
,请你返回完成旅行的 最小费用 ,如果无法在 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[i−c][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][n−1]
代码
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;
}
};