C++编程:23、 给定一棵有n个节点且节点编号为1到n的树,求满足以下条件的路径组合数: 1. 从节点a到节点b的路径(称为路径ab) 边数为p 2. 从节点c到节点d的路径(称为路径cd)边数为q 3. 路径ab和cd不交,即不存在一个节点既在路径ab又在路径 cd上
时间: 2024-03-14 10:45:51 浏览: 132
以下是树上组合计数问题的 C++ 代码实现:
```cpp
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 100005;
int n, p, q, a, b, c, d, ans;
vector<int> G[MAXN];
int depth[MAXN], fa[MAXN];
int dp1[MAXN][20], dp2[MAXN][20];
void dfs(int u, int f, int d) {
depth[u] = d;
fa[u] = f;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (v != f) {
dfs(v, u, d + 1);
}
}
}
void init() {
dfs(1, 0, 1);
for (int i = 1; i <= n; i++) {
dp1[i][0] = dp2[i][0] = fa[i];
}
for (int j = 1; j < 20; j++) {
for (int i = 1; i <= n; i++) {
dp1[i][j] = dp1[dp1[i][j - 1]][j - 1];
dp2[i][j] = dp2[dp2[i][j - 1]][j - 1];
}
}
}
int lca(int u, int v) {
if (depth[u] < depth[v]) {
swap(u, v);
}
for (int i = 19; i >= 0; i--) {
if (depth[dp1[u][i]] >= depth[v]) {
u = dp1[u][i];
}
}
if (u == v) {
return u;
}
for (int i = 19; i >= 0; i--) {
if (dp1[u][i] != dp1[v][i]) {
u = dp1[u][i];
v = dp1[v][i];
}
}
return fa[u];
}
void dp(int u, int f) {
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (v != f) {
dp(v, u);
for (int j = 0; j < 20; j++) {
dp1[u][j] += dp1[v][j];
dp2[u][j] += dp2[v][j];
}
}
}
}
int main() {
cin >> n >> a >> b >> p >> c >> d >> q;
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
init();
int e = lca(a, b);
for (int i = 19; i >= 0; i--) {
if (depth[dp1[a][i]] >= depth[e] + p) {
a = dp1[a][i];
}
}
for (int i = 19; i >= 0; i--) {
if (depth[dp1[b][i]] >= depth[e] + p) {
b = dp1[b][i];
}
}
e = lca(c, d);
for (int i = 19; i >= 0; i--) {
if (depth[dp2[c][i]] >= depth[e] + q) {
c = dp2[c][i];
}
}
for (int i = 19; i >= 0; i--) {
if (depth[dp2[d][i]] >= depth[e] + q) {
d = dp2[d][i];
}
}
dp(1, 0);
ans = dp1[a][0] + dp1[b][0] + dp2[c][0] + dp2[d][0] - 2 * dp1[lca(a, b)][0] - 2 * dp1[lca(c, d)][0];
cout << ans << endl;
return 0;
}
```
这段代码首先读入节点数 n、路径 ab 和 cd 的信息,然后读入 n - 1 条边,建立树的邻接表表示。接下来,使用深度优先搜索计算出每个节点的深度 depth 和父节点 fa,然后使用倍增算法预处理出每个节点的 $2^k$ 级祖先 dp1 和 dp2。最后,计算出路径 ab 和 cd 的公共祖先 e,然后向上找到距离 e 距离为 p 的节点 a 和 b,以及距离 e 距离为 q 的节点 c 和 d。使用深度优先搜索计算出每个节点到根节点路径上的节点数,然后根据公式计算出路径 ab 和 cd 不交的方案数。
阅读全文