道路与航线——图论综合性最短路问题,综合性太强把他单独拎出来了

道路与航线–dfs+topsort+dijkstra+建图方式

算法流程

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;

typedef long long LL;
typedef pair<int, int> PII;
#define x first
#define y second

const int N = 25010,M=150010;
int h[N],e[M],ne[M],w[M],idx=0;

int dist[N];
bool st[N];
vector<int>block[N];
int bcnt=0;
int id[N];
int n,rm,pm,s;
int din[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)
{
    memset(st, 0, sizeof st);
    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;
        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]==0)
        {
            q.push(i);
        }
    }
    while(q.size())
    {
        int t=q.front();
        q.pop();
        dij(t);
    }
}
int main()
{
    memset(h,-1,sizeof h);
    cin>>n>>rm>>pm>>s;
    int a,b,c;
    while(rm--)
    {
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    
    for(int i=1;i<=n;i++)
    {
        if(!id[i])
        {
            dfs(i,++bcnt);
        }
    }
    
    while(pm--)
    {
        cin>>a>>b>>c;
        din[id[b]]++;
        add(a,b,c);
    }
    topsort();
    for(int i=1;i<=n;i++)
    {
        if(dist[i]>0x3f3f3f3f/2)cout<<"NO PATH"<<endl;
        else cout<<dist[i]<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_WAWA鱼_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值