本题是在非负权值图中求解最短路径,典型的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];
}
};
Dijkstra算法与动态规划在非负权值图中最短路径数计算
文章介绍了如何在非负权值图中使用改进的Dijkstra算法求解最短路径,并结合动态规划思想记录最短路径数目。通过优先队列实现,展示了求解过程中的递推规则和代码实现。

832

被折叠的 条评论
为什么被折叠?



