力扣每日一题:Dijkstra1976.到达目的地的方案数

Dijkstra算法与动态规划在非负权值图中最短路径数计算
文章介绍了如何在非负权值图中使用改进的Dijkstra算法求解最短路径,并结合动态规划思想记录最短路径数目。通过优先队列实现,展示了求解过程中的递推规则和代码实现。

本题是在非负权值图中求解最短路径,典型的Dijkstra算法的应用,只不过在求解最短路径时,还需要记录最短路径数目。这个又涉及到一点动态规划的思想。
考虑一个点u,原点到u的最短路径为dis[u],最短路径数目为ways[u],那么对于u的连通点v,又u到v的权值k,然后原点到v的最短路径是dis[v],最短路径数目为ways[v]。
那么从u到v,有如下递推公式

  1. 当dis[v] > dis[u]+k时,应当更新dis[v] = dis[u]+k。并且ways[v] = ways[u]
  2. 当dis[v] = dis[u]+k时,不需要更新,ways[v] += ways[u]
  3. 当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];
    }
};
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值