[题目链接]
[算法]
首先,我们预处理出每个点到第N个点的最短路,这等价于在反图上求第N个点到其余点的最短路
然后,我们用f[u][k]表示从第u个点到第n个点,至多走长度为dist(u,n) + k的路径有多少种走法
记忆化搜索即可,注意判断是否存在0环
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 100010 #define MAXM 200010 #define MAXK 55 const int INF = 2e9; int i,j,tot,ans,u,v,w,T,N,M,K,P; int head[MAXN],rhead[MAXN],dist[MAXN]; int f[MAXN][MAXK]; bool visited[MAXN][MAXK]; bool flag; struct Edge { int to,w,nxt; } e[MAXM << 1]; inline void addedge(int u,int v,int w) { tot++; e[tot] = (Edge){v,w,head[u]}; head[u] = tot; tot++; e[tot] = (Edge){u,w,rhead[v]}; rhead[v] = tot; } inline void dijkstra(int s) { int i,v,w,cur; priority_queue< pair<int,int> > q; static bool visited[MAXN]; while (!q.empty()) q.pop(); for (i = 1; i <= N; i++) { dist[i] = INF; visited[i] = false; } dist[s] = 0; q.push(make_pair(0,s)); while (!q.empty()) { cur = q.top().second; q.pop(); if (visited[cur]) continue; visited[cur] = true; for (i = rhead[cur]; i; i = e[i].nxt) { v = e[i].to; w = e[i].w; if (dist[cur] + w < dist[v]) { dist[v] = dist[cur] + w; q.push(make_pair(-dist[v],v)); } } } } inline int dp(int now,int k) { int i,v,w,tmp,cnt,ret; if (f[now][k] != -1) return f[now][k]; if (now == N) ret = 1; else ret = 0; if (visited[now][k]) return -1; visited[now][k] = true; for (i = head[now]; i; i = e[i].nxt) { v = e[i].to; w = e[i].w; tmp = k - (dist[v] + w - dist[now]); if (tmp < 0) continue; cnt = dp(v,tmp); if (cnt == -1) { flag = true; return -1; } else ret = (ret + cnt) % P; } visited[now][k] = false; return f[now][k] = ret; } int main() { scanf("%d",&T); while (T--) { scanf("%d%d%d%d",&N,&M,&K,&P); tot = 0; for (i = 1; i <= N; i++) head[i] = rhead[i] = 0; for (i = 1; i <= M; i++) { scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); } dijkstra(N); flag = false; for (i = 1; i <= N; i++) { for (j = 0; j <= K; j++) { f[i][j] = -1; visited[i][j] = false; } } ans = dp(1,K); if (flag) printf("-1 "); else printf("%d ",ans); } return 0; }