道路与航线--dfs+topsort+dijkstra+建图

本文介绍了一种算法,通过深度优先搜索(DFS)划分道路网络连通块,并利用拓扑排序处理航线,计算每个连通块的入度,实现连通块内的Dijkstra算法求最短路径。关键步骤包括初始化、航线统计、连通块处理和拓扑排序。
摘要由CSDN通过智能技术生成

在这里插入图片描述
在这里插入图片描述

算法流程

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

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 25010,M=150010,INF=0x3f3f3f3f;
typedef pair<int, int> PII;
#define x first
#define y second
int e[M],h[N],ne[M],w[M],idx=0;
int n,mr,mp,s;
int bcnt;
vector<int>block[N];
int id[N];
int din[N];
int dist[N];
bool st[N];
queue<int>q;
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 bid)
{
    id[u]=bid,block[bid].push_back(u);
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!id[j])
            dfs(j,bid);
    }
}
void dij(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.y,distance=t.x;
        if(st[ver])continue;
        st[ver]=true;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(id[j]!=id[ver]&&--din[id[j]]==0)q.push(id[j]);
            if(dist[j]>dist[ver]+w[i]){
                dist[j]=dist[ver]+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(!din[i])
            q.push(i);
    while(q.size())
    {
        int t=q.front();
        q.pop();
        dij(t);
    }
}
signed main()
{
    memset(h, -1, sizeof h);
    cin>>n>>mr>>mp>>s;
    for(int i=1;i<=mr;i++)
    {
        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);
        }
    for(int i=1;i<=mp;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        din[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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_WAWA鱼_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值