1 条题解
-
0
题目理解
我们有一个 个节点的有向图,要求计算从起点 到终点 恰好经过 条边的路径数量,其中:
- 起点和终点各只访问一次
- 中间节点可以重复访问
- 边可以重复经过
问题转化
设 表示从 到 恰好走 步的路径总数(允许重复访问所有节点)。
但题目要求起点和终点各只访问一次,这意味着:
- 路径中不能提前到达终点(否则终点就访问了多次)
- 路径中不能提前回到起点(否则起点就访问了多次)
关键定义
代码中定义了四个关键数组:
- : 从 到 走 步的路径总数(无限制)
- : 从 到 走 步,且只在最后一步到达 (终点只访问一次)
- : 从 回到 走 步,且不经过
- : 从 回到 走 步,不经过 ,且起点只访问两次(开始和结束)
递推关系
1. 基础计数
g[x][x][0] = 1; for (int d = 1; d <= D; d++) { for (int i = 1; i <= n; i++) { for (auto u : v[i]) { g[x][u][d] += g[x][i][d - 1]; } } }这就是简单的路径计数:
2. 终点只出现一次
f[s][t][d] = g[s][t][d]; for (int j = 1; j < d; j++) { f[s][t][d] = (f[s][t][d] - f[s][t][j] * g[t][t][d - j]) % Mod; }这里用容斥原理:从所有路径中减去那些提前到达终点的路径。
- : 第一次到达 是在第 步
- : 从 开始在剩下的 步中随意走(可能多次回到 )
3. 不经过终点的环
e[s][t][d] = g[s][s][d]; for (int j = 1; j < d; j++) { e[s][t][d] = (e[s][t][d] - f[s][t][j] * g[t][s][d - j]) % Mod; }从所有回到 的路径中,减去那些经过 的路径。
4. 起点只出现两次的环
h[s][t][d] = e[s][t][d]; for (int j = 1; j < d; j++) { h[s][t][d] = (h[s][t][d] - h[s][t][j] * e[s][t][d - j]) % Mod; }用容斥确保起点只在开始和结束出现:从所有不经过 的环中,减去那些中间回到起点的环。
5. 最终答案
ans[s][t][d] = f[s][t][d]; for (int j = 1; j < d; j++) { ans[s][t][d] = (ans[s][t][d] - h[s][t][j] * f[s][t][d - j]) % Mod; }从终点只出现一次的路径中,减去那些中间回到起点的路径(因为起点只能出现一次)。
算法流程
- 预处理 数组:对每个起点 ,计算到所有节点走 到 步的路径数
- 递推计算 数组
- 处理查询:直接输出
时间复杂度
- 预处理 :
- 递推 :
- 查询:
由于 , ,这在时间限制内可行。
算法标签
- 动态规划
- 容斥原理
- 递推
- 图结构
总结
该算法通过巧妙的容斥和递推关系,解决了带有起点终点访问次数限制的固定长度路径计数问题。核心思想是将复杂约束分解为多个子问题,逐步应用容斥原理得到最终答案。
- 1
信息
- ID
- 3629
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者