一、题目
1、题目描述
你在一个城市里,城市由
n
个路口组成,路口编号为0
到n - 1
,某些路口之间有 双向 道路。输入保证你可以从任意路口出发到达其他任意路口,且任意两个路口之间最多有一条路。给你一个整数
n
和二维整数数组roads
,其中roads[i] = [ui, vi, timei]
表示在路口ui
和vi
之间有一条需要花费timei
时间才能通过的道路。你想知道花费 最少时间 从路口0
出发到达路口n - 1
的方案数。请返回花费 最少时间 到达目的地的 路径数目 。由于答案可能很大,将结果对
109 + 7
取余 后返回。
2、接口描述
cpp
class Solution {
public:
int countPaths(int n, vector<vector<int>>& roads) {
}
};
3、原题链接
二、解题报告
1、思路分析
比较经典的最短路问题
对于所有的最短路上的每一个点都满足沿着路径到源点的距离最短
思考我们的Dijkstra算法,只有dist[u] + w < dist[v]时会更新,而对于dist[u] + w = dist[v]的情况选择略去,而我们如果利用这一点便可以累加最短路数目
定义f[u]为s到u的最短路数目
执行Dijkstra
如果dist[u] + w < dist[v],那么f[v] = f[u],更新距离的同时v入堆
如果dist[u] + w = dist[v],那么f[v] += f[u],不更新距离也不入堆
2、复杂度
时间复杂度:O(mlogm) 空间复杂度:O(m)
3、代码详解
cpp
class Solution {
public:
typedef long long ll;
typedef pair<ll, ll> pll;
ll f[205], dist[205], mod = 1e9 + 7;
int countPaths(int n, vector<vector<int>>& roads) {
vector<vector<pll>> g(n);
for(auto& e : roads) g[e[0]].emplace_back(e[1], e[2]), g[e[1]].emplace_back(e[0], e[2]);
memset(f, 0, sizeof f), memset(dist, 0x3f, sizeof dist);
priority_queue<pll, vector<pll>, greater<pll>> pq;
dist[0] = 0, f[0] = 1, pq.emplace(0, 0);
while(pq.size()){
auto [d, u] = pq.top(); pq.pop();
if(d > dist[u]) continue;
for(auto [v, w] : g[u]){
if(d + w < dist[v]) f[v] = f[u], pq.emplace(dist[v] = d + w, v);
else if(d + w == dist[v]) f[v] = (f[v] + f[u]) % mod;
}
}
return f[n - 1];
}
};