Description
Input
Output
Example
input
2
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
2 2 0 10
1 2 0
2 1 0
output
3
-1
思路
本题题意为求长度为
d
,
d
+
1
,
d
+
2......
,
d
+
k
d,d+1,d+2......,d+k
d,d+1,d+2......,d+k的路线数量,我们发现
k
k
k的范围非常小,可以枚举
k
k
k的值。
对于一个点
x
x
x,到终点的最短距离为
d
i
s
[
x
]
dis[x]
dis[x],对于一个点
y
y
y,到终点的最短距离为
d
i
s
[
y
]
dis[y]
dis[y],它们之间的距离为
x
x
x到
y
y
y边的权重
w
w
w,即可得出从
x
x
x经过
y
y
y到达终点多余的花费为
c
o
s
t
=
d
i
s
[
y
]
+
w
−
d
i
s
[
x
]
cost=dis[y]+w-dis[x]
cost=dis[y]+w−dis[x]
即可得到递推公式
d
p
[
x
]
[
j
]
=
∑
d
p
[
y
]
[
j
−
c
o
s
t
]
dp[x][j] = \sum dp[y][j-cost]
dp[x][j]=∑dp[y][j−cost],其中
j
j
j代表当前状态下剩余可消耗的路径长度,然后记忆化搜索即可,如果一个点在同一条路径中被判断了多次,则出现了0环直接退出即可
代码
#include <bits/stdc++.h>
#define ll long long
#define mem(s,i) memset(s,i,sizeof s)
#define pii pair<long long,long long>
#define endl "\n"
using namespace std;
const int N = 1e5+4;
const int inf = 1e9;
int head[N],cnt=0,n,m,k,p,u[N<<1],v[N<<1],w[N<<1];
int dp[N][55],vis1[N][55];
struct edge
{
int to,next,w;
} e[N<<1];
bool huan;
struct node
{
int dis;
int pos;
bool operator <( const node &x )const
{
return x.dis < dis;
}
};
int dis[N],vis[N];
void dijkstra(int s)
{
mem(dis,0x3f);
priority_queue<node> pq;
dis[s] = 0;
pq.push({0, s});
while (!pq.empty())
{
node t = pq.top();
pq.pop();
int x = t.pos, d = t.dis;
if (vis[x]) continue;
vis[x] = 1;
for (int i = head[x]; i != -1; i = e[i].next)
{
int y = e[i].to;
if (dis[y] > dis[x] + e[i].w)
{
dis[y] = dis[x] + e[i].w;
// if (!vis[y])
// {
pq.push({dis[y], y});
// }
}
}
}
}
void add(int u,int v,int w)
{
e[cnt].to=v,e[cnt].next=head[u],e[cnt].w=w,head[u]=cnt++;
}
ll dfs(int pos,int d)
{
if(vis1[pos][d])
{
huan = true;
return 0;
}
if(dp[pos][d] != -1) return dp[pos][d];
vis1[pos][d] = 1;
ll res = 0;
for(int i = head[pos]; i!=-1; i = e[i].next)
{
int v = e[i].to;
int cost = dis[v] + e[i].w - dis[pos];
if(d - cost < 0 || d - cost > k) continue;
res = (res + dfs(v,d-cost))%p;
if(huan) return 0;
}
vis1[pos][d] = 0;
if(pos == n && d == 0) res = 1;
dp[pos][d] = res%p;
return res%p;
}
void solve()
{
huan = false;
mem(head,-1);
cin >> n >> m >> k >> p;
for(int i = 1; i <= m; i++)
{
cin >> u[i] >> v[i] >> w[i];
add(v[i],u[i],w[i]);
}
mem(vis,0);
dijkstra(n);
cnt = 0;
mem(head,-1);
mem(dp,-1);
mem(vis1,0);
for(int i = 1; i <= m; i++)
{
add(u[i],v[i],w[i]);
}
ll res = 0;
for(int i = 0; i <= k; i++)
{
res = (res + dfs(1,i))%p;
if(huan) break;
}
if(huan) cout << -1 << endl;
else cout << res << endl;
}
int main()
{
int t = 1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}