题目链接
https://www.luogu.org/problemnew/show/P3953
觉得是dp,想了一个n*最短路长度的dp
发现数组开不下……
而且我也不知道怎么在图上做dp
然后就写了个K=0的情况,写了个最短路计数,水了30分
同时写了个spfa判环,但是因为是多组数据所以没得分
奋战了大概5 6 个小时,终于把这道题弄透并AC
为什么效率怎么低……
我应该自己画图理解,试着把思路讲出来,理解透这个过程,然后AC也就是理所当然的事情了
具体思路网上一大把,我讲几个非常精彩的地方
(1)看到k比较小,所以可以把k当作状态的一维, dp[u][k]表示从n走到u比最短路多走k的方案数
(2)反向边可以用结构体套结构体的方式写,非常秀
(3)判断有没有环的时候注意是再搜到一次,同时在栈里面
(4)注意初始化是正向图,dp是反向图,这样连起来恰好构成一条从1到n的路径
(5)网上很多题解写的是建立反向图防止跑到到不了n的点浪费时间
但是如果建反向图的话岂不是会跑到到不了1的点浪费时间???
所以建立反向图是为了和从1出发的最短路构成一条从1到n的路径
其实正向图,然后最短路是从n开始出发,也一样。
(5)然后主函数dfs只用写一次就好了,一次就能把所有的值算出来,看到很多代码是枚举k的
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; const int MAXN = 1e5 + 10; int d[MAXN], n, p, m, k; int dp[MAXN][60], vis[MAXN][60]; struct graph { struct Edge { int to, w, next; }; Edge e[MAXN << 1]; int head[MAXN], tot; inline void init() { memset(head, -1, sizeof(head)); tot = 0; } inline void AddEdge(int from, int to, int w) { e[tot] = Edge{to, w, head[from]}; head[from] = tot++; } }G[2]; void read(int& x) { int f = 1; x = 0; char ch = getchar(); while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); } while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } x *= f; } struct node { int id, w; bool operator < (const node& rhs) const { return w > rhs.w; } }; void dijkstra() { priority_queue<node> q; q.push(node{1, 0}); _for(i, 1, n) d[i] = i == 1 ? 0 : 1e9; while(!q.empty()) { node x = q.top(); q.pop(); if(x.w != d[x.id]) continue; int u = x.id; for(int i = G[0].head[u]; ~i; i = G[0].e[i].next) { int v = G[0].e[i].to, w = G[0].e[i].w; if(d[v] > d[u] + w) { d[v] = d[u] + w; q.push(node{v, d[v]}); } } } } int dfs(int u, int k) { if(vis[u][k]) return -1; if(dp[u][k] != -1) return dp[u][k]; vis[u][k] = 1; int sum = 0; for(int i = G[1].head[u]; ~i; i = G[1].e[i].next) { int v = G[1].e[i].to, w = G[1].e[i].w, kk, t; kk = k - (d[v] + w - d[u]); if(kk < 0) continue; if((t = dfs(v, kk)) == -1) return -1; sum = (sum + t) % p; } if(u == 1) sum++; vis[u][k] = 0; return dp[u][k] = sum % p; } int main() { int T; read(T); while(T--) { G[0].init(); G[1].init(); memset(dp, -1, sizeof(dp)); memset(vis, 0, sizeof(vis)); read(n); read(m); read(k); read(p); _for(i, 1, m) { int u, v, w; read(u); read(v), read(w); G[0].AddEdge(u, v, w); G[1].AddEdge(v, u, w); } dijkstra(); printf("%d ", dfs(n, k)); } return 0; }