道路与航线(最短路+拓扑排序)

题意

有一些有向边,还有一些无向边,已知不存在回路,求起点到其他各点的最短距离。

数据范围

卡spfa

思路(参考acwing)

这题脑洞比较大,但是思想较为深刻。因为不存在回路,所以可以将一些通过无向边相连的点看成一个块,然后这些块通过有向边形成一个有向图。也就是说,局部是无向图,全局是有向图。
然后,对全局做拓扑排序,块的内部做Dijkstra。算法步骤如下:

  • 先输入所有双向道路,然后等方式求出所有连通块,计算出两个数组:每个点属于哪个连通块,每个连通块有哪些点。
  • 输入所有航线,同时统计出每个连通块的入度。
  • 按照拓扑序一次处理每个连通块。先将所有入度为0的连通块的编号加入队列中。
  • 每次从队头取出一个连通块的编号bid
  • 将该块中的所有点加入堆中,然后对堆中所有点跑Dijkstra算法。
  • 每次取出堆中距离最小的点ver
  • 然后遍历ver的所有邻点j,如果id[ver] == id[j],那么如果j能被更新,则将j插入堆中;如果id[ver] != id[j],则将id[j]这个连通块的入度减1,如果减成0了,则将其插入拓扑排序的队列中。

代码

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

using namespace std;

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

typedef pair<int,int> pii;

int n,R,P,S;
int h[N], e[M], ne[M], w[M], idx;
int dist[N], id[N];
bool st[N];
int bin[N];
int bcnt;
vector<int> block[N];
queue<int> que;

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

void dfs(int u,int k)
{
    
    
    block[k].push_back(u);
    id[u] = bcnt;
    for(int i=h[u];~i;i=ne[i]){
    
    
        int j = e[i];
        if(!id[j]){
    
    
            dfs(j,k);
        }
    }
}

void dijkstra(int bid)
{
    
    
    priority_queue<pii,vector<pii>,greater<pii>> heap;
    for(auto u:block[bid]){
    
    
        heap.push({
    
    dist[u],u});
    }
    while(heap.size()){
    
    
        auto t = heap.top();
        heap.pop();
        int ver = t.second, distance = t.first;
        if(st[ver]) continue;
        st[ver] = true;
        for(int i=h[ver];~i;i=ne[i]){
    
    
            int j = e[i];
            if(id[j]!=id[ver]&&--bin[id[j]]==0) que.push(id[j]);
            if(dist[j]>distance+w[i]){
    
    
                dist[j] = distance + w[i];
                if(id[j]==id[ver]){
    
    
                    heap.push({
    
    dist[j],j});
                }
            }
        }
    }
}

void topsort()
{
    
    
    memset(dist,0x3f,sizeof(dist));
    dist[S] = 0;
    for(int i=1;i<=bcnt;i++)
        if(!bin[i])
            que.push(i);
    while(que.size()){
    
    
        int t = que.front();
        que.pop();
        dijkstra(t);
    }
}

int main()
{
    
    
    cin >> n >> R >> P >> S;
    memset(h,-1,sizeof(h));
    while(R--){
    
    
        int a,b,c;
        cin >> a >> b >> c;
        add(a,b,c), add(b,a,c);
    }
    for(int i=1;i<=n;i++)
        if(!id[i])
        {
    
    
            bcnt ++;
            dfs(i,bcnt);
        }
    while(P--){
    
    
        int a,b,c;
        cin >> a >> b >> c;
        add(a,b,c);
        bin[id[b]] ++;
    }
    topsort();
    for(int i=1;i<=n;i++){
    
    
        if(dist[i]>inf/2) cout << "NO PATH" << endl;
        else cout << dist[i] << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43634220/article/details/108607996