StkOvflow

STACK OVERFLOW!

一言(ヒトコト)

zc大人我错了!
——wjd

AcWing342. 道路与航线

原题链接

解题思路

这题用SPFA会被卡,所以我们不能用SPFA
但是观察数据我们可以发现对于道路,0Ci105
所以对于每个连通块(内部不存在航线),我们可以用Dijkstra算法进行求解,因为不存在负权边,而Dijkstra算法的时间较为稳定,所以对于连通块内部的最短路,我们采用Dijkstra
块内问题解决了,但是块间呢
保证如果有一条航线可以从AiBi,那么保证不可能通过一些道路和航线从 Bi 回到 Ai
我们将每个连通块看做一个大点
那么根据上述性质,我们可以得到这张由大点为点,航线为边的图是一张拓扑图(DAG)
那么DAG的最短路我们可以按照它的拓扑序扫描求出最短路
为什么呢
因为我们利用拓扑序进行DP,那后来的节点一定是无法更新前面的节点,这样就可以确保无后效性,因此可以正确求出最短路

解题步骤

1.先输入所有的双向道路,然后用dfs求出所有的连通块,用id[]数组统计每个数所在的连通块编号,用一个vector<int> block[]来保存每个编号的连通块里存的点
2.输入所有的航线,再输入的同时可以统计每个连通块的入度
3.拓扑排序
4.按照拓扑序对每个连通块进行Dijkstra算法
5.Dijkstra步骤:
(1)每次从堆中取出一个点t
(2)遍历t的所有出边,同一个连通块的进行松弛操作,不同连通块的将对方连通块入度1,如果1后连通块的入度为0,插入拓扑序队列中(所以拓扑序的队列要开成全局的)

代码

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

using namespace std;
typedef pair<int, int> PII;

const int N = 25010, M = 2e5 + 10, INF = 0x3f3f3f3f;
int h[N], e[M], w[M], ne[M], idx;
int dist[N], id[N], st[N], din[N];
int n, mr, mp, S, bcnt;

vector<int> block[M];
queue<int> q;

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

void dfs(int u, int bid) 
{
    id[u] = bid, block[bid].push_back(u);

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

void Dijkstra(int bid) 
{
    priority_queue<PII, vector<PII>, greater<> > heap;

    for (auto u : block[bid]) 
        heap.push({dist[u], u});

    while (heap.size()) 
    {
        auto t = heap.top().second; heap.pop();

        if (st[t]) continue ;
        st[t] = true ;

        for (int i = h[t]; ~i; i = ne[i]) 
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i]) 
            {
                dist[j] = dist[t] + w[i];
                if (id[j] == id[t]) heap.push({dist[j], j});
            }

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

void topsort() 
{
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;

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

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

int main()
{
    scanf("%d%d%d%d", &n, &mr, &mp, &S);

    memset(h, -1, sizeof h);
    memset(st, 0, sizeof st);

    while (mr -- ) 
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w), add(v, u, w);
    }

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

    while (mp -- ) 
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w), din[id[v]] ++ ;
    }

    topsort();

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

    return 0;
}
posted @   StkOvflow  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示