<h1>题意描述</h1>
给定一张无向图,定义 $ S $ 为 $ 1 $ 到 $ N $ 的最短路,求该无向图 $ 1 $ 到 $ N $ 的路径中长度小于等于 $ S+K $ 的方案。
推荐大家去 uoj 多交一些题目,上面有很多 hack 数据。(像我之前认为 dij 就是 spfa+priority_queue)。
<h1>解题报告</h1>
这一题我们首先一定要跑一遍从 $n$ 到 $1$ 的最短路,记录下 $n$ 到 $i$ 的最短路径长度 $dis_i$
我们考虑动态规划。最长为 $N+k$ 可以理解为你可以多跑长度 $k$。
这样我们写一个 dfs 来搜索,然后无脑记忆化一下。
设 $f[v][i]$ 表示到第 $v$ 个点,走目前的路+之后走最短路到达终点的花费大于最短路不超过 $k$ 的路径条数。
深搜到每一个点的时候如果这一个点是 $n$ 就当前状态记录的答案 $ +1$。枚举这个点指向的点 $next$ 和出边 $w$,转移有 $f[v][i] \to f[next][dis_{next}+w-dis_v]$ 。
为什么从 $n$ 跑到 $1$ 的原因就是避免掉那些走不到终点的点也加入状态。
然后判断无限多解。只需要一个状态在同一条路径中出现了两次就有无限多种解了。
<h3>代码</h3>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define Re register
#define LL long long
#define U unsigned
#define FOR(i,a,b) for(Re int i = a;i <= b;++i)
#define ROF(i,a,b) for(Re int i = a;i >= b;--i)
#define SFOR(i,a,b,c) for(Re int i = a;i <= b;i+=c)
#define SROF(i,a,b,c) for(Re int i = a;i >= b;i-=c)
#define CLR(i,a) memset(i,a,sizeof(i))
#define BR printf("--------------------n")
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
const int MAXN = 100000 + 5;
const int MAXM = 200000 + 5;
int N,M,K,P;
struct Node{
struct Edge *firstEdge;
int dist,num;
bool used;
}node[MAXN],rnode[MAXN];
struct Edge{
Node s,t;
int w;
Edge *next;
}pool[MAXM<<1],*frog = pool;
Edge New(Node s,Node *t,int w){
Edge *ret = ++frog;
ret->s = s;ret->t = t;ret->w = w;
ret->next = s->firstEdge;
return ret;
}
inline void add(int u,int v,int w){
node[u].firstEdge = New(&node[u],&node[v],w);
rnode[v].firstEdge = New(&rnode[v],&rnode[u],w);
}
#define P std::pair<int,Node *>
#define MP std::make_pair
inline void dij(){
std::priority_queue<P,std::vector<P>,std::greater<P> >q;
FOR(i,1,N){
node[i].num = rnode[i].num = i;
rnode[i].dist = INT_MAX;
rnode[i].used = false;
}
q.push(MP(rnode[N].dist=0,&rnode[N]));
while(!q.empty()){
Node *v = q.top().second;q.pop();
if(v->used) continue;
v->used = true;
for(Edge *e = v->firstEdge;e;e = e->next){
if(e->t->dist > v->dist + e->w){
e->t->dist = v->dist + e->w;
q.push(MP(e->t->dist,e->t));
}
}
}
}
int fMAXN;
int visMAXN;
int ha;
int dfs(Node *v,int k){
if(visv->num) return -1;
if(fv->num) return fv->num;
visv->num = true;
fv->num = (v->num == N) ? 1 : 0;
for(Edge *e = v->firstEdge;e;e = e->next){
int t = rnode[e->t->num].dist+e->w-rnode[v->num].dist;
if(t <= k && t >= 0){
int res = dfs(e->t,k-t);
if(res == -1) return fv->num = -1;
fv->num = (fv->num + res)%ha;
}
}
visv->num = false;
return fv->num;
}
inline void Solve(){
CLR(f,0);CLR(vis,false);
frog = pool;
scanf("%d%d%d%d",&N,&M,&K,&ha);
CLR(node,0);CLR(rnode,0);
FOR(i,1,M){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
dij();
int ans = dfs(&node[1],K);
printf("%dn",ans);
}
int main(){
int T;scanf("%d",&T);
while(T--) Solve();
return 0;
}