题意
求 d i s ( 1 , n ) < = M i n D i s ( 1 , n ) + K dis(1,n)<=MinDis(1,n)+K dis(1,n)<=MinDis(1,n)+K的路径数
题解
算法一:
首先你可以考虑到 D a y 1 Day1 Day1的 D P DP DP去哪里了?
没错,你只要再注意一下 K ≤ 50 K\le50 K≤50就大概能想到这是一个与 k k k有关的 D P DP DP了
①:考虑$30pts:K=0 $
右转LuoguP1608路径统计(P1144最短路计数可以顺带A掉)
②:考虑 70 p t s 70pts 70pts:没有 0 0 0边
设 d i s 1 u dis1_u dis1u表示1到u的最短路, d i s n u disn_u disnu表示 u u u到 n n n的最短路(这个可以建反图跑出来)
考虑 f [ u ] [ j ] f[u][j] f[u][j]表示 d i s ( 1 , u ) ≤ d i s 1 u + j dis(1,u)\le dis1_u+j dis(1,u)≤dis1u+j的路径数
那么对于 e d g e ( u , v , w ) edge(u,v,w) edge(u,v,w)
那么从 1 − > u − > v 1->u->v 1−>u−>v这条路径的长度就是 d i s 1 u + j + w − d i s 1 v dis1_u+j+w-dis1_v dis1u+j+w−dis1v
如果 d i s 1 u + w − d i s 1 v + j ≤ K dis1_u+w-dis1_v+j\le K dis1u+w−dis1v+j≤K
就可以从 f [ u ] [ j ] f[u][j] f[u][j]转移到 f [ v ] [ d i s 1 u + j + w − d i s 1 v ] f[v][dis1_u+j+w-dis1_v] f[v][dis1u+j+w−dis1v]
所以直接先从 1 1 1跑最短路然后直接 O ( K M ) D P O(KM)DP O(KM)DP就 o k ok ok了
当然这样还是有问题的
因为我们必须要先更新 d i s 1 dis1 dis1小的点
所以要先按照 d i s 1 dis1 dis1排个序再去转移就有 70 p t s 70pts 70pts了
③:考虑 100 p t s : 100pts: 100pts:
对于有 0 0 0边的图,显然直接按照 d i s 1 dis1 dis1去排序是不行的
例如 a − > b − > c , w = 0 a->b->c,w=0 a−>b−>c,w=0
因为他的一个有向图,更新顺序显然是 a , b , c a,b,c a,b,c
所以考虑拓扑排序来确定 0 0 0边两个端点的更新顺序
即对于 0 0 0边,把其加入新图,然后对于新图拓扑排序确定" 0 0 0点"的更新顺序
然后对于 − 1 -1 −1的情况显然是对于一条满足条件的路径上有一个 0 0 0环
拓扑排序完了且入度不等于 0 0 0说明这个点在 0 0 0环上
同一个 0 0 0环上任意一个点到 1 1 1的最短路和到 n n n的最短路都一样
所以当这个点 i i i满足 d i s 1 i + d i s n i < = d i s 1 n + K dis1_i+disn_i<=dis1_n+K dis1i+disni<=dis1n+K时,就可以输出 − 1 -1 −1了
然后最后以 d i s 1 dis1 dis1或 d i s n disn disn为第一关键字,拓扑序为第二关键字排序再转移就 o k ok ok了
算法二:
只要跑一次反向的最短路
f [ u ] [ k ] f[u][k] f[u][k]表示 d i s ( u , n ) < = M i n D i s ( u , n ) + k dis(u,n)<=MinDis(u,n)+k dis(u,n)<=MinDis(u,n)+k的方案数,答案就是 f [ 1 ] [ K ] f[1][K] f[1][K]
考虑 e g d e ( u , v , w ) egde(u,v,w) egde(u,v,w)
同样的道理走这条边的话, d i s ( v , n ) = M i n D i s ( v , n ) + w − M i n D i s ( u , n ) dis(v,n)=MinDis(v,n)+w-MinDis(u,n) dis(v,n)=MinDis(v,n)+w−MinDis(u,n)
⇒ f [ u ] [ k ] = ∑ f [ v ] [ k − ( M i n D i s ( v , n ) − M i n D i s ( u , n ) + w ) ] \Rightarrow f[u][k]=∑f[v][k-(MinDis(v,n)-MinDis(u,n)+w)] ⇒f[u][k]=∑f[v][k−(MinDis(v,n)−MinDis(u,n)+w)]
这样怎么判 0 0 0环呢?只要在搜索的时候记录个 i n s t a c k instack instack就 o k ok ok了
如果当前的 v v v还在搜索的栈中就可以直接返回 − 1 -1 −1了