道路与航线

题目

传送门

分析

1.在这里插入图片描述
3. 时间复杂度分析
每个连通块跑一遍dij_heap, m1logn1 + m2logn2 + … + milogni, 我们将他放缩一下 < (m1+m2+…+mi)logn = mlogn

AC代码

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

typedef pair<int, int> pii;

const int N = 25010, M = 200010, inf = 0x3f3f3f3f;

int n, mr, ms, s;
int h[N], w[M], e[M], ne[M], idx;
int id[N]; // 记录每个点属于的连通分量
int cnt;  // 连通分量的数量
int dis[N];
bool st[N];
queue<int> q;
vector<int> block[N]; // 连通块数组
int d[N]; // 连通块的入度数组

void add (int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}

void dij_heap(int u)
{
    priority_queue<pii, vector<pii>, greater<pii>> pq;

    for(int i = 0 ; i < block[u].size() ; i ++ )
    	pq.push({dis[block[u][i]], block[u][i]});
    	
    /*
    上一个连通块是由起点拓展出来的最短距离,现连通块的起点也是由是一个连通块的点拓展出来的,所以距离也是到起点的距离
    所以拓展出来的距离都是到起点的距离
    */
    while(pq.size())
    {
        auto t = pq.top();
        pq.pop();

        int x = t.first, y = t.second;

        if(st[y]) continue;
        st[y] = 1;

        for(int i = h[y] ; i != -1 ; i = ne[i])
        {
            int j = e[i];

            if(dis[j] > x + w[i])
            {
                dis[j] = x + w[i];
                if(id[j] == id[y]) pq.push({dis[j], j}); // 同一连通块才放进优先队列,防止了出现负权边, dijkstra无法解决
            }

            if (id[j] != id[y] && -- d[id[j]] == 0) q.push(id[j]); 
        }
    }
}

void top_sort()
{
    // memset整张图就将其串成了一张单源最短路的图
    memset(dis, 0x3f, sizeof dis);
    dis[s] = 0;

    for(int i = 1 ; i <= cnt ; i ++ )
        if(!d[i])
            q.push(i);

    while(q.size())
    {
        int t = q.front();
        q.pop();
        dij_heap(t);
    }
}

void dfs (int u, int v)  // 标记每个点所属的连通分量的编号
{
    id[u] = v;
    block[v].push_back(u);

    for(int i = h[u] ; i != -1 ; i = ne[i])
    {
        int j = e[i];
        if(!id[j]) dfs(j, v);
    }
}

int main ()
{
    scanf("%d%d%d%d", &n, &mr, &ms, &s);

    memset(h, -1, sizeof h);
    for(int i = 0 ; i < mr ; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);

        add(a, b, c);
        add(b, a, c);
    }

    for(int i = 1 ; i <= n ; i ++ )
        if(!id[i])
            dfs(i, ++ cnt);

    for(int i = 0 ; i < ms ; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);

        add(a, b, c);
        d[id[b]] ++ ;
    }

    top_sort();

    for(int i = 1 ; i <= n ; i ++ )
        if(dis[i] > inf / 2) 
            puts("NO PATH");
        else printf("%d\n", dis[i]);

    return 0;
}
发布了52 篇原创文章 · 获赞 22 · 访问量 1694

猜你喜欢

转载自blog.csdn.net/qq_45792080/article/details/105439390