LuoguP3953 逛公园(最短路+dp)
逛公园
题目:
策策同学特别喜欢逛公园。公园可以看成一张 个点 条边构成的有向图,且没有 自环和重边。其中 号点是公园的入口, 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从 号点进去,从 号点出来。策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果 号点 到 号点的最短路长为 ,那么策策只会喜欢长度不超过 的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?为避免输出过大,答案对 取模。如果有无穷多条合法的路线,请输出 。
思路:
因为题目保证了从 到 一定是可以到达的,而且同时还要知道最短路的长 ,就不难想到要跑一遍最短路,但是我们要知道其他能够到达 的方案的路径长度,所以连边的时候不能够用无向边来存储,需要建两个图(正图,反图), 正图用来跑出来 的最短路的长度,反图用来处理相差不超过 的方案。
int n, m, k, p;
std::cin >> n >> m >> k >> p;
//建出正反图
std::vector<std::vector<std::array<int, 2>>> g1(n + 1);
std::vector<std::vector<std::array<int, 2>>> g2(n + 1);
for (int i = 0; i < m; i++) {
int u, v, w;
std::cin >> u >> v >> w;
g1[u].push_back({v, w});
g2[v].push_back({u, w});
}
// Dijkstra算法
std::priority_queue<std::array<int, 2>, std::vector<std::array<int, 2>>, std::greater<std::array<int, 2>>> q;
q.push({0, 1});
std::vector<int> dist(n + 1, 1E9);
std::vector<bool> vis(n + 1);
dist[1] = 0;
while(q.size()) {
auto [w, u] = q.top(); q.pop();
if (vis[u]) continue;
vis[u] = true;
for (auto& [v, ww] : g1[u]) {
if (dist[v] > dist[u] + ww) {
dist[v] = dist[u] + ww;
q.push({dist[v], v});
}
}
}
由于最终要求的是方案数,并且同样有相差不超过 的额外限制,所以考虑用 来求解方案数。定义状态为 代表从 的路径中长度为 的方案数。现在考虑状态的转移,假设现在要从 ,也就是 也就是 。这样 就可以从 转移过来。在反图上跑一遍 ,用记忆化搜索的方式会比较好写,
std::vector<std::vector<bool>> st(n + 1, std::vector<bool> (k + 1));
std::vector<std::vector<int>> dp(n + 1, std::vector<int> (k + 1));
int f = 0;
std::function<int(int, int)> dfs = [&](int u, int now) -> int {
if (now < 0) return 0;
if (st[u][now]) { f = 1; return 0; }
if (dp[u][now]) return dp[u][now];
st[u][now] = true;
int ans = 0;
for (auto& [v, w] : g2[u]) {
ans = (ans + dfs(v, dist[u] - dist[v] + now - w)) % p;
if (f) return 0;
}
st[u][now] = false;
return dp[u][now] = ans;
};
dfs(1, 0);
dp[1][0] = 1;
int ans = 0;
for (int i = 0; i <= k; i++) {
ans = (ans + dfs(n, i)) % p;
}
if (f == 1) return void(std::cout << "-1\n");
std::cout << ans << "\n";
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端