原题链接:https://loj.ac/problem/2316
逛公园
题目描述
策策同学特别喜欢逛公园。 公园可以看成一张 N N N个点 M M M条边构成的有向图,且没有自环和重边。其中 1 1 1号点是公园的入口, N N N号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从 1 1 1号点进去,从 N N N号点出来。
策策喜欢新鲜的事物,他不希望有两天逛公园的路线完全一样,同时策策还是一个特别热爱学习的好孩子,他不希望每天在逛公园这件事上花费太多的时间。如果 1 1 1号点到 N N N号点的最短路长为 d d d,那么策策只会喜欢长度不超过 d + K d + K d+K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮他吗?
为避免输出过大,答案对 P P P取模。
如果有无穷多条合法的路线,请输出 − 1 −1 −1。
输入格式
第一行包含一个整数 T T T, 代表数据组数。
接下来 T T T组数据,对于每组数据:
第一行包含四个整数 N , M , K , P N,M,K,P N,M,K,P, 每两个整数之间用一个空格隔开。
接下来 M M M行,每行三个整数 a i , b i , c i a_i,b_i,c_i ai,bi,ci , 代表编号为 a i , b i a_i,b_i ai,bi的点之间有一条权值为 c i c_i ci 的有向边,每两个整数之间用一个空格隔开。
输出格式
输出文件包含 T T T行,每行一个整数代表答案。
样例
样例输入
2
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
2 2 0 10
1 2 0
2 1 0
样例输出
3
-1
样例解释
对于第一组数据,最短路为 3 3 3。
1 − 5 , 1 − 2 − 4 − 5 , 1 − 2 − 3 − 5 1 - 5, 1 - 2 - 4 - 5, 1 - 2 - 3 - 5 1−5,1−2−4−5,1−2−3−5为 3 3 3条合法路径。
数据范围与提示
对于不同测试点,我们约定各种参数的规模不会超过如下
测试点编号 | T T T | N N N | M M M | K K K | 是否有 0 0 0边 |
---|---|---|---|---|---|
1 1 1 | 5 5 5 | 5 5 5 | 10 10 10 | 0 0 0 | 否 |
2 2 2 | 5 5 5 | 1000 1000 1000 | 2000 2000 2000 | 0 0 0 | 否 |
3 3 3 | 5 5 5 | 1000 1000 1000 | 2000 2000 2000 | 50 50 50 | 否 |
4 4 4 | 5 5 5 | 1000 1000 1000 | 2000 2000 2000 | 50 50 50 | 否 |
5 5 5 | 5 5 5 | 1000 1000 1000 | 2000 2000 2000 | 50 50 50 | 否 |
6 6 6 | 5 5 5 | 1000 1000 1000 | 2000 2000 2000 | 50 50 50 | 是 |
7 7 7 | 5 5 5 | 100000 100000 100000 | 200000 200000 200000 | 0 0 0 | 否 |
8 8 8 | 3 3 3 | 100000 100000 100000 | 200000 200000 200000 | 50 50 50 | 否 |
9 9 9 | 3 3 3 | 100000 100000 100000 | 200000 200000 200000 | 50 50 50 | 是 |
10 10 10 | 3 3 3 | 100000 100000 100000 | 200000 200000 200000 | 50 50 50 | 是 |
对于 100 % 100\% 100% 的数据: 1 ≤ P ≤ 1 0 9 , 1 ≤ a i , b i ≤ N , 0 ≤ c i ≤ 1000 1\le P \le 10^9,1 \le a_i,b_i \le N ,0 \le c_i \le 1000 1≤P≤109,1≤ai,bi≤N,0≤ci≤1000。
数据保证:至少存在一条合法的路线。
题解
看到 K ≤ 50 K\leq 50 K≤50不禁想到 d p dp dp, d p [ i ] [ j ] dp[i][j] dp[i][j]表示第 i i i个点,还剩长度为 j j j的路可以绕的方案数,容易想到记忆化搜索来更新,如果 d f s dfs dfs出环就返回 − 1 -1 −1。
另外,为了得到绕路的"标准",我们需要每个点到 n n n的最短路,所以需要在反向图上跑一遍以 n n n为起点的最短路。
代码
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
struct sd{int to,w;}ed[M<<2],ed2[M<<2];
bool operator<(sd a,sd b){return a.w>b.w;}
int head[M],nxt[M<<2],head2[M],nxt2[M<<2],dis[M],dp[M][55],T,n,m,k,p,cnt,cnt2;
bool vis[M],vis2[M][55];
priority_queue<sd>dui;
void add(int f,int t,int w){nxt[++cnt]=head[f],head[f]=cnt,ed[cnt]=(sd){t,w};}
void add2(int f,int t,int w){nxt2[++cnt2]=head2[f],head2[f]=cnt2,ed2[cnt2]=(sd){t,w};}
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));memset(dis,127,sizeof(dis));dui.push((sd){s,dis[s]=0});
for(sd f;!dui.empty();)
{
f=dui.top();dui.pop();if(vis[f.to])continue;vis[f.to]=1;
for(int i=head[f.to];i;i=nxt[i])if(!vis[ed[i].to]&&dis[ed[i].to]>dis[f.to]+ed[i].w)
dis[ed[i].to]=dis[f.to]+ed[i].w,dui.push((sd){ed[i].to,dis[ed[i].to]});
}
}
int dfs(int v,int r)
{
if(vis2[v][r])return -1;
if(dp[v][r])return dp[v][r];
vis2[v][r]=1;if(v==n)dp[v][r]=1;
for(int i=head2[v],d,w;i;i=nxt2[i])
if((d=dis[ed2[i].to]-dis[v]+ed2[i].w)<=r)
{
if((w=dfs(ed2[i].to,r-d))==-1)return dp[v][r]=-1;
(dp[v][r]+=w)%=p;
}
return vis2[v][r]=0,dp[v][r];
}
void reset(){memset(head,cnt=0,sizeof(head));memset(head2,cnt2=0,sizeof(head2));memset(vis2,0,sizeof(vis2));memset(dp,0,sizeof(dp));}
void in(){scanf("%d%d%d%d",&n,&m,&k,&p);for(int i=1,a,b,c;i<=m;++i)scanf("%d%d%d",&a,&b,&c),add(b,a,c),add2(a,b,c);}
void ac(){dijkstra(n);printf("%d\n",dfs(1,k));}
int main(){for(scanf("%d",&T);T--;)reset(),in(),ac();}