K<=50,感觉可以DP
先建反图求出从n到各个点的最短路,然后在正图上DP
设f[当前点][比最短路多走的距离]=方案数
转移显然是 $f[v][res]=sum f[u][res+tmp]$ tmp是从v到u比最短路多走的路程
注意如果图中有0环,则有无穷多种方案。
判0环可以DFS判,也可以把最短路边和0权边建在一个新图上,用拓扑排序判(显然前者更简单)
1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cmath> 6 #include<cstring> 7 #include<queue> 8 using namespace std; 9 const int mxn=100010; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 struct edge{ 17 int v,nxt,w; 18 }e[mxn<<1],er[mxn<<1]; 19 int hd[mxn],mct=0; 20 int hdr[mxn],rct=0; 21 void add_edge(int u,int v,int w){ 22 e[++mct].v=v;e[mct].nxt=hd[u];e[mct].w=w;hd[u]=mct;return; 23 } 24 void add_edgeR(int u,int v,int w){ 25 er[++rct].v=v;er[rct].nxt=hdr[u];er[rct].w=w;hdr[u]=rct;return; 26 } 27 int dis[mxn]; 28 bool inq[mxn]; 29 int vis[mxn]; 30 queue<int>q; 31 int n,m,K,P; 32 void SPFA(int s){//反图SPFA 33 memset(dis,0x3f,sizeof(dis)); 34 dis[s]=0; 35 q.push(s); 36 while(!q.empty()){ 37 int u=q.front();q.pop();inq[u]=0; 38 for(int i=hdr[u];i;i=er[i].nxt){ 39 int v=er[i].v; 40 if(dis[v]>dis[u]+er[i].w){ 41 dis[v]=dis[u]+er[i].w; 42 if(!inq[v]){ inq[v]=1; q.push(v); } 43 } 44 } 45 } 46 return; 47 } 48 inline void add(int &a,int b){ 49 a+=b; a=(a>P)?(a-P):a; return; 50 } 51 int f[mxn][51]; 52 int ind[mxn];//时间戳 53 int cir; 54 int DP(int u,int res){ 55 // printf("in:%d %d ",u,res); 56 if(vis[u] && ind[u]==res){cir=1;return 0;} 57 if(f[u][res]!=-1)return f[u][res]; 58 int tmp=0; 59 if(u==n && !res)tmp++;//return 1影响判环 60 vis[u]++; 61 ind[u]=res; 62 // 63 for(int i=hd[u];i;i=e[i].nxt){ 64 int v=e[i].v; 65 int x=res-(e[i].w-(dis[u]-dis[v])); 66 if(x>=0 && x<=K) 67 add(tmp,DP(v,x)); 68 if(cir)return 0; 69 } 70 // 71 vis[u]--; 72 ind[u]=0; 73 return f[u][res]=tmp; 74 } 75 void init(){ 76 memset(f,-1,sizeof f); 77 memset(hd,0,sizeof hd); 78 memset(hdr,0,sizeof hdr); 79 memset(ind,0,sizeof ind); 80 memset(vis,0,sizeof vis); 81 mct=0;rct=0;cir=0; 82 return; 83 } 84 int main(){ 85 int i,j,u,v,w,ans; 86 int T=read(); 87 while(T--){ 88 init(); 89 n=read();m=read();K=read();P=read(); 90 for(i=1;i<=m;i++){ 91 u=read();v=read();w=read(); 92 add_edge(u,v,w); 93 add_edgeR(v,u,w); 94 } 95 SPFA(n); 96 ans=0; 97 for(i=0;i<=K;i++){ 98 add(ans,DP(1,i)); 99 if(cir)break; 100 } 101 if(cir) puts("-1"); 102 else printf("%d ",ans); 103 } 104 return 0; 105 }