本题是在非负权值图中求解最短路径,典型的Dijkstra算法的应用,只不过在求解最短路径时,还需要记录最短路径数目。这个又涉及到一点动态规划的思想。
考虑一个点u,原点到u的最短路径为dis[u],最短路径数目为ways[u],那么对于u的连通点v,又u到v的权值k,然后原点到v的最短路径是dis[v],最短路径数目为ways[v]。
那么从u到v,有如下递推公式
- 当dis[v] > dis[u]+k时,应当更新dis[v] = dis[u]+k。并且ways[v] = ways[u]
- 当dis[v] = dis[u]+k时,不需要更新,ways[v] += ways[u]
- 当dis[v]较小时,不需要操作
本题代码如下
class Solution {
public:using LL =long long;class cmp{public:bool operator()(const pair<int,LL>& a,const pair<int, LL>& b){return a.second > b.second;}};int countPaths(int n, vector<vector<int>>& roads) {const LL mod = 1e9+7;//建图vector<vector<pair<int,LL>>> graph(n);for(auto& road : roads){graph[road[0]].push_back({road[1],road[2]});graph[road[1]].push_back({road[0],road[2]});}//结果数组vector<LL> dis(n,LLONG_MAX);dis[0] = 0;vector<LL> ways(n,1);vector<int> visited(n);//优先队列priority_queue<pair<int,LL>,vector<pair<int,LL>>,cmp> q;q.push({0,0});while(!q.empty()){pair<int,LL> temp = q.top();q.pop();int cur = temp.first;int curdis = temp.second;//如果当前权值 大于已记录的值 跳过if(curdis > dis[cur]) continue;//如果cur被访问过跳过if(visited[cur]) continue;visited[cur] = 1;for(auto& y : graph[cur]){//连通点int next = y.first;LL n_dis = y.second;if(dis[next] > dis[cur] + n_dis){dis[next] = dis[cur] + n_dis;ways[next] = ways[cur];q.push({next,dis[next]});}else if(dis[next] == dis[cur]+n_dis){ways[next] = (ways[next] + ways[cur]) % mod;}}}return ways[n-1];}
};