P3953 [NOIP2017 提高组] 逛公园

P3953 [NOIP2017 提高组] 逛公园

总算把咕了快四年的题A了QAQ。

题意

给出 N,M,K,PN, M, K, P,一个包含 NN 个点 MM 条边的有向图,没有自环和重边,顶点编号从 1N1\sim N

dis(u,v)dis(u, v) 为从 uu 出发到达 vv 的最短路径,求从顶点 11 到顶点 NN 的路程小于等于 dis(1,N)+Kdis(1, N) + K 的路径数目。

答案对 PP 取模。

思路

计数问题又可以考虑dp了,先用dijkstra算法求出顶点 11 到每个顶点的最短距离。

f(u,j)f(u, j) 表示,从顶点 11 到顶点 uu 距离满足小于等于 dis(1,u)+jdis(1, u)+j 的路径数目,jj 也就是当前距离和最短距离在容许范围内的最大差值。

考虑一条有向边 (u,v)(u, v),边权为 wu,vw_{u,v},则转移为:

f(v,dis(1,u)+j+wu,vdis(1,v))+=f(u,j)f(v, dis(1, u) + j + w_{u, v} - dis(1, v)) += f(u, j)

其中 dis(1,u)+j+wu,vdis(1,v)dis(1, u) + j + w_{u, v} - dis(1, v) 表示在 dis(1,u)+jdis(1, u) + j 的基础上加上权值 wu,vw_{u,v} 后获得的总距离,再和最短距离 dis(1,v)dis(1, v) 做差获得差值,当差值非负的时候就能进行转移。

由于上式不好直接正推出来,所以考虑记忆化搜索实现dp的转移,于是将上式改写成:

f(u,j)+=f(v,j+dis(1,u)dis(1,v)wv,u)f(u, j) += f(v, j + dis(1, u) - dis(1, v) - w_{v, u})

于是先反向建图,然后在反向图中进行记忆化搜索即可。

关于零环的判断,只要在记忆化搜索中,判断 f(u,j)f(u, j) 有没有在同一次搜索中出现两次即可,因为如果出现两次,当且仅当通过路程上的点的最短距离都相等,且边权值都为0,这就一定是0环了。

而且这样不会被卡数据,因为这不是直接去找0环,而是在满足 j0j\geqslant 0 的前提下去找的,这样就保证了这个0环一定是可以到达的

解释一下可以到达的含义:如果 KK 特别小,比如是 K=0K=0,如果在1到N的最短路外出现了一个零环,对答案是没有任何影响的,因为你根本走不到这个位置。

注: 构造了一个特殊原点编号为0,它向顶点1连接一条边权为0的有向边,这样在记忆化搜索中,就不会找到 f(1,0)f(1, 0) 就提前返回了,而没有判断顶点1是否是在0环中。

初始化:f(0,0)=0f(0,0)= 0


P3953 [NOIP2017 提高组] 逛公园
https://wty-yy.github.io/posts/55933/
作者
wty
发布于
2021年8月24日
许可协议