题目描述见链接 .
首先 求出从 节点到所有节点的 最短路,
设 表示从 到 路径长度为最短路长度加 长度的方案数,
则 ,
发现状态转移的顺序有些麻烦, 于是从 号节点开始 记忆化搜索,
若现在在更新 , 而又搜到了 , 则可以判断有 无穷解 .
#include<bits/stdc++.h>
#define reg register
#define se second
#define fi first
typedef std::pair <int, int> pr;
const int maxn = 100005;
const int inf = 0x3f3f3f3f;
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
int N;
int M;
int K;
int mod;
int num0;
int dis[maxn];
int cnt[maxn];
int head[maxn];
int F[maxn][55];
bool vis[maxn];
bool used[maxn][55];
struct Edge{ int nxt, to, w; } edge[maxn*3], E[maxn*3];
void Add(int from, int to, int w){ edge[++ num0] = (Edge){ head[from], to, w }; head[from] = num0; }
void Dij(){
std::priority_queue <pr, std::vector<pr>, std::greater<pr> > Q;
for(reg int i = 1; i <= N; i ++) dis[i] = inf, vis[i] = 0;
Q.push(pr(0, 1)); dis[1] = 0;
while(!Q.empty()){
int ft = Q.top().se; Q.pop();
if(vis[ft]) continue ; vis[ft] = 1;
for(reg int i = head[ft]; i; i = edge[i].nxt){
int to = edge[i].to;
if(dis[to] > dis[ft] + edge[i].w){
dis[to] = dis[ft] + edge[i].w;
Q.push(pr(dis[to], to));
}
}
}
}
bool FLAG;
int DFS(int k, int a){
if(FLAG) return 0;
if(a > K || a < 0) return 0;
if(k == 1 && !a) return 1;
if(used[k][a]) return FLAG=1;
if(~F[k][a]) return F[k][a];
used[k][a] = 1; int s = 0;
for(reg int i = head[k]; i; i = edge[i].nxt){
int to = edge[i].to;
s = (s + DFS(to, dis[k]+a-edge[i].w-dis[to])) % mod;
}
used[k][a] = 0;
return F[k][a] = s;
}
void Work(){
N = read(), M = read(), K = read(), mod = read();
for(reg int i = 1; i <= N; i ++) head[i] = 0; num0 = 0;
for(reg int i = 1; i <= M; i ++){
int x = read(), y = read(), c = read();
Add(x, y, c);
E[i].nxt = x, E[i].to = y, E[i].w = c;
}
Dij();
for(reg int i = 1; i <= N; i ++)
for(reg int j = 0; j <= K; j ++) F[i][j] = -1;
for(reg int i = 1; i <= N; i ++) head[i] = 0; num0 = 0;
for(reg int i = 1; i <= N; i ++)
for(reg int a = 0; a <= K; a ++) used[i][a] = 0;
for(reg int i = 1; i <= M; i ++) Add(E[i].to, E[i].nxt, E[i].w);
int Ans = 0; FLAG = 0;
for(reg int a = 0; a <= K && !FLAG; a ++) Ans = (Ans + DFS(N, a)) % mod;
if(FLAG) return printf("-1
"), void();
printf("%d
", Ans);
}
int main(){ //多测不清空,爆零两行泪 .
// 无解----------------------
freopen("park.in", "r", stdin);
freopen("park.out", "w", stdout);
int T = read();
while(T --) Work();
return 0;
}