Acwing 342:道路与航线 (含有无环负权边的最短路问题 dijkstra+topsort)题解

题目大意

原题链接:Acwing 342:道路与航线

各城市之间有道路也有航线,道路是双向的且权值为正,航线是单向的且权值有负,保证航线连接的两个城市ab,只能从a到b,而不能以任何途径从b到a,路的权值是花费。
给定一个起点,求从起点到其余所有城市的最小花费。

思路

根据题意,所有道路相连的城市都是一个连通的无向图,将这样的城市群看作一个团,整张图会有很多个团,每个团之间有单向的边,权值可能是负数,如下图,黑边是道路,红边是航线:
eg
既有正边又有负边的单源最短路问题应该怎么做?dij不能处理负权边,因此肯定首先会想到spfa,但spfa已死 ,很容易被一个菊花图卡掉,这道题就被卡掉了。所以我们就要看这个图的性质。每个团内部可以用堆优化的dijstra来求最短路,而每个团之间一定无环(题意,没有任何途径从航线终点到航线起点),那么将每个团做一个拓扑排序,然后线性的扫描一遍,就可以处理团之间的边了。我们用id数组存每个点所属的团的编号,block的vector数组来存每个团内有哪些点。
然后按照拓扑序对每个团内的点做一遍堆优化的dij边拓扑排序边做dij:当团内dij时若访问到团外的点,就将点所在的团的入度减一(topsort),然后正常更新dis数组即可。(具体步骤可以看代码详解)

这样子就灵活的处理掉了dij不能处理负权边的问题,因为所有团是按拓扑序排的,所以线性的扫一遍求最短路是没问题的。而每个团做dij时,将当前点走到的点记为v,若v是团内的点就正常更新dis,判断入堆即可;若v是团外的点,则该边可能是负数,我们就直接更新dis[v]即可,然后将v所在团的入度减一,若入度为0,将v所在的团加入拓扑序列。然后我们判断若dis[i] > INF/2,就说明没有路到i点,因为若i的团在起点的团的拓扑序的前面,且i之前有团用负边更新到了i点,因此i点的距离可能比INF小一点,所以只需用一个较大的数来判断,我们取INF/2来判断,若大于他,都说明没有路,输出NO PATH,其余输出dis[i]即可。

代码详解

#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N = 25010,M = 150010,INF = 0x3f3f3f3f;

int n,r,p,s;
int e[M],ne[M],w[M],h[N],idx;	//链式前向星建图
int id[N],dis[N],d[N],bcnt;		//id是每个点所属的连通块编号,dis是到各点的距离,d是入度,bcnt是连通块编号
bool vis[N];	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值