题目描述
策策同学特别喜欢逛公园。公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从N号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到N
号点的最短路长为d,那么策策只会喜欢长度不超过d+K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对P取模。
如果有无穷多条合法的路线,请输出−1。
输入输出格式
输入格式:
第一行包含一个整数 T, 代表数据组数。
接下来T组数据,对于每组数据: 第一行包含四个整数 N,M,K,P,每两个整数之间用一个空格隔开。
接下来M行,每行三个整数ai,bi,ci,代表编号为ai,bi的点之间有一条权值为 ci的有向边,每两个整数之间用一个空格隔开。
输出格式:
输出文件包含 T 行,每行一个整数代表答案。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
首先反向边跑dij求每个点到终点最短路,然后记忆化搜索转移。
注意最后跑一遍搜-1 。
代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100050 #define M 200050 inline int rd() { int f = 1,c = 0;char ch = getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=(c<<1)+(c<<3)+ch-'0';ch=getchar();} return f*c; } int T,n,m,K,P,hed[N],cnt,ihed[N],icnt; struct EG { int to,w,nxt; }ie[M],e[M]; void ae(int f,int t,int v) { e[++cnt].to = t; e[cnt].w = v; e[cnt].nxt = hed[f]; hed[f] = cnt; } void aie(int f,int t,int v) { ie[++icnt].to = t; ie[icnt].w = v; ie[icnt].nxt = ihed[f]; ihed[f] = icnt; } int dis[N]; bool vis[N]; struct node { int x,d; node(){} node(int x,int d):x(x),d(d){} friend bool operator < (node a,node b) { return a.d>b.d; } }tp; bool ot; /*void ck(int u) { if(vis[u]) { ot=1; return ; } vis[u]=1; for(int j=ihed[u];j;j=ie[j].nxt) { int to = ie[j].to; if(dis[to]>=dis[u]+ie[j].w) { dis[to]=dis[u]+ie[j].w; ck(to); if(ot)return ; } } vis[u]=0; }*/ priority_queue<node>q; void dij() { memset(dis,0x3f,sizeof(dis)); dis[n]=0; q.push(node(n,0)); while(!q.empty()) { tp = q.top(); q.pop(); int u = tp.x; if(vis[u])continue; vis[u]=1; for(int j=ihed[u];j;j=ie[j].nxt) { int to = ie[j].to; if(dis[to]>dis[u]+ie[j].w) { dis[to]=dis[u]+ie[j].w; q.push(node(to,dis[to])); } } } } int dp[N][55]; bool vs[N][55]; int dfs(int u,int k) { if(dp[u][k]!=-1)return dp[u][k]; vs[u][k]=1; dp[u][k] = 0; for(int to,tmp,j=hed[u];j;j=e[j].nxt) { to = e[j].to; tmp = k-dis[to]+dis[u]-e[j].w; if(tmp<0)continue; if(vs[to][tmp])ot=1; (dp[u][k]+=dfs(to,tmp))%=P; } vs[u][k]=0; return dp[u][k]; } void init() { memset(hed,0,sizeof(hed)); memset(ihed,0,sizeof(ihed)); memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); memset(dp,-1,sizeof(dp)); cnt=icnt=0; ot=0; } int main() { T=rd(); while(T--) { init(); n=rd(),m=rd(),K=rd(),P=rd(); for(int u,v,w,i=1;i<=m;i++) { u=rd(),v=rd(),w=rd(); ae(u,v,w); aie(v,u,w); } dis[n]=1; // ck(n); // if(ot) // { // printf("-1 "); // continue; // } dij(); dp[n][0]=1; int ans = 0; for(int k=0;k<=K&&ot==0;k++) { (ans+=dfs(1,k))%=P; } dfs(1,K+1); if(ot)printf("-1 "); else printf("%d ",ans); } return 0; }