📌  相关文章
📜  门| Sudo GATE 2020 Mock II(2019 年 1 月 10 日)|问题 8(1)

📅  最后修改于: 2023-12-03 15:28:47.015000             🧑  作者: Mango

门 | Sudo GATE 2020 Mock II(2019 年 1 月 10 日)|问题 8

概述

本题是一道考察图论算法的题目,需要求出从某个起点S开始,遍历整个图的最短路径。

问题描述

给定一个由n个节点和m条边组成的有向无环图,请你找到从S节点开始遍历整个图的最短路径。每条边都有一个权重,代表遍历这条边需要的时间,起点S节点到其他节点的距离均为正整数。

解题思路

这是一个典型的单源最短路径的问题,我们可以考虑使用Dijkstra算法或者Bellman-Ford算法进行求解。

Dijkstra算法需要保证边的权重为非负数,而Bellman-Ford算法能够处理边权重为负数的情况。但是由于本题保证距离是正整数,因此我们选择使用Dijkstra算法进行求解。

Dijkstra算法的基本思想是维护一个集合S,其中的节点已经被确定了最短路径,而其余的节点还没有确定。初始状态下,S集合只有起点S。每次从集合V-S中,选择一个距离起点S最近的节点u加入集合S中,然后更新S集合中节点的距离值。

具体的,我们可以使用一个长度为n的dist数组,表示某个节点到起点S的距离,初始状态下dist[S]=0,其他节点的dist都是无穷大。每次选择最小的dist值对应的节点u,然后更新S集合中节点的距离值,即对于每个u的未访问的邻居v,如果dist[v]>dist[u]+w(u,v),则dist[v]=dist[u]+w(u,v)。

进行n次操作后,求出所有节点到起点S的最短距离,这就是结果。

实现需要用到一个优先队列,可以使用STL中的priority_queue进行实现。

代码如下:

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

const int INF = 1e9;  // 表示无穷大
typedef pair<int, int> P;  // 用于存储节点和其到起点的距离

void dijkstra(int s, vector<vector<P>>& g, vector<int>& dist)
{
    dist[s] = 0;
    priority_queue<P, vector<P>, greater<P>> q;
    q.push(make_pair(0, s));

    while(!q.empty()){
        P p = q.top();
        q.pop();
        int v = p.second;
        if(dist[v] < p.first) continue;
        for(auto& it: g[v]){
            int u = it.first;
            int ww = it.second;
            if(dist[u] > dist[v]+ww){
                dist[u] = dist[v]+ww;
                q.push(make_pair(dist[u], u));
            }
        }
    }
}

int main()
{
    int n, m, s;
    cin >> n >> m >> s;
    vector<vector<P>> g(n);
    vector<int> dist(n, INF);
    for(int i=0; i<m; ++i){
        int u, v, w;
        cin >> u >> v >> w;
        g[u].push_back(make_pair(v, w));
    }

    dijkstra(s, g, dist);

    for(int i=0; i<n; ++i){
        if(dist[i]==INF) cout << "INF" << endl;  // 无法到达
        else cout << dist[i] << endl;
    }
    return 0;
}
时间复杂度分析

使用Dijkstra算法,时间复杂度为O(mlogn)。其中m表示边的数量,n表示节点数量。本题中,m和n取值范围分别为1<=m,n<=10^4,因此算法的时间复杂度是可行的。