策策同学特别喜欢逛公园。公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从NN号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对PP取模。
如果有无穷多条合法的路线,请输出-1−1。
题解:
这道题首先看到最短路先搞一个堆优
然后看到k只有50
嗯嗯嗯好像就可以dp了然后我又不会了
然后看了一下好像就只会dfs判0环
然后就看题解了。。
dp[u][k] 表示到u比最短路小于等于k的总方案数
那么到n所有小于等于k的方案数都应该计入答案,dp[n][k] = 1
考虑走一步对于答案的影响
首相原来在u这个点,到最短路的距离是dis[u]
然后走到v这个点后,那么当前方案对于u来说走的最短距离就是f[i] + dis[v]
那么对于这个方案,最短距离是dis[u],当前方案是dis[v] + f[i],多出来的就是 dis[v] + f[i] - dis[u]
每次对于当前的kk来说去找v的kk - dis[v] - f[i] + dis[u],用记忆化搜索就可以解决了
然后对于0环的情况,就是一个kk绕了一圈又回到这里计算答案,记录一下这个地方是否有过这个状态在递归栈中,如果有就拜拜了
贴上代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int read() {
int rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
rt = (rt << 1) + (rt << 3) + ch - '0';
ch = getchar();
}
return rt * f;
}
struct Node {
int val, id;
bool operator < (const Node &rhs) const {
return val > rhs.val;
}
};
priority_queue<Node> q;
const int maxn = 1e5 + 5;
const int maxm = 2e5 + 5;
int h1[maxn], h2[maxn], tot1, tot2, dis[maxn], dp[maxn][55];
bool ins[maxn][55];
int n, m, k, p, T;
struct Edge {
int nxt, tov, f;
}e1[maxm], e2[maxm];
void init() {
tot1 = tot2 = 0;
memset(h1, 0, sizeof(h1));
memset(h2, 0, sizeof(h2));
memset(dp, 0, sizeof(dp));
memset(ins, 0, sizeof(ins));
}
void add1(int u, int v, int w) {
tot1++;
e1[tot1].tov = v;
e1[tot1].nxt = h1[u];
e1[tot1].f = w;
h1[u] = tot1;
}
void add2(int u, int v, int w) {
tot2++;
e2[tot2].tov = v;
e2[tot2].nxt = h2[u];
e2[tot2].f = w;
h2[u] = tot2;
}
void di() {
while (!q.empty()) q.pop();
for (int i = 1; i <= n; i++) dis[i] = 1e9;
dis[n] = 0;
q.push((Node){0, n});
while (!q.empty()) {
Node u = q.top();
q.pop();
if (u.val != dis[u.id]) continue;
for (int i = h2[u.id]; i; i = e2[i].nxt) {
int v = e2[i].tov;
if (dis[v] > dis[u.id] + e2[i].f) {
dis[v] = dis[u.id] + e2[i].f;
q.push((Node){dis[v], v});
}
}
}
}
int dfs(int u, int kk) {
if (ins[u][kk]) return dp[u][kk] = -1;
if (dp[u][kk]) return dp[u][kk];
ins[u][kk] = 1;
if (u == n) dp[u][kk] = 1;
else dp[u][kk] = 0;
for (int i = h1[u]; i; i = e1[i].nxt) {
int v = e1[i].tov;
if (kk >= dis[v] + e1[i].f - dis[u]) {
int tmp = dfs(v, kk - dis[v] - e1[i].f + dis[u]);
if (tmp == -1) return dp[u][kk] = -1;
else dp[u][kk] += tmp, dp[u][kk] %= p;
}
}
ins[u][kk] = 0;
return dp[u][kk];
}
int main() {
T = read();
while (T--) {
init();
n = read(), m = read(), k = read(), p = read();
for (int i = 1; i <= m; i++) {
int u, v, w;
u = read(), v = read(), w = read();
add1(u, v, w);
add2(v, u, w);
}
di();
int ans = dfs(1, k);
printf("%d\n", ans);
}
return 0;
}