无
2026-09-13 18:50:50
发布于:江西
0阅读
0回复
0点赞
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
typedef long long ll;
const int MAXN = 55; // 顶点数
const int MAXM = 20; // 约束数
vector<pair<int, int>> G[MAXN]; // 树:邻接表存 (to, edge_id)
ll edge_mask[MAXM]; // 第i个约束路径对应的边集合(二进制mask)
int N, M;
// BFS 找 u->v 路径上的所有边,返回二进制mask
ll get_path_mask(int u, int v) {
queue<int> q;
int from[MAXN], eid[MAXN]; // from: 前驱点 eid: 前驱边
memset(from, -1, sizeof(from));
q.push(u);
from[u] = u;
while (!q.empty()) {
int x = q.front(); q.pop();
if (x == v) break;
for (auto [y, id] : G[x]) {
if (from[y] == -1) {
from[y] = x;
eid[y] = id;
q.push(y);
}
}
}
// 回溯路径,收集边
ll mask = 0;
int cur = v;
while (cur != u) {
mask |= 1LL << eid[cur];
cur = from[cur];
}
return mask;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> N;
// 给边编号 0 ~ N-2
for (int i = 0; i < N-1; i++) {
int a, b;
cin >> a >> b;
G[a].emplace_back(b, i);
G[b].emplace_back(a, i);
}
cin >> M;
for (int i = 0; i < M; i++) {
int u, v;
cin >> u >> v;
edge_mask[i] = get_path_mask(u, v);
}
// 容斥原理:枚举所有子集
ll ans = 0;
for (int s = 0; s < (1 << M); s++) {
int cnt = __builtin_popcount(s); // 子集大小
ll union_e = 0; // 这些约束对应的边的并集
// 合并所有选中约束的边集
for (int i = 0; i < M; i++) {
if (s & (1 << i)) union_e |= edge_mask[i];
}
ll free = (N-1) - __builtin_popcountll(union_e);
ll ways = 1LL << free;
// 容斥系数:(-1)^cnt
if (cnt % 2 == 0) ans += ways;
else ans -= ways;
}
cout << ans << endl;
return 0;
}
这里空空如也





有帮助,赞一个