标签:int image inline 两种 signed fine roc return alt
给你n个点n条边的图,让你求树上的简单路径数。
简单路径:从a->b的方法,需要注意的是1->2>3,3->2->1算一种
显然建成后的图是一棵树多了一条边,这种图又叫环基树。
从下图开始分析该题:
我们假设这个环的每一个点都是一棵树,我们建图。
在每个以环上的点为根的树上的任意两个点只有\(C_n^2\)的取法
其他的任意两个点间的取法都是有两种路径共计\(C_n^2 * 2\)。
我们先假设任意两个点间都有两种到达方法那么,\(ans = C_n^2\)
然后我们再减去只有一种方法的路径,即为所求。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//#define int long long
const int maxn = 2e5 + 10;
int deg[maxn], bfs[maxn];
vector<int>edge[maxn];
int f[maxn], num[maxn];
void init(int n) {
for (int i = 1; i <= n; ++i) {
f[i] = i; num[i] = 1;
}
}
int find(int x) {
return f[x] == x ? x : f[x] = find(f[x]);
}
bool Union(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy) return 0;
if (num[fx] > num[fy]) swap(fx, fy);
num[fy] += num[fx];
f[fx] = fy;
return 1;
}
bool is_root(int x) {
return f[x] == x ? 1 : 0;
}
void solve() {
int n; cin >> n;
init(n);
for (int i = 1; i <= n; ++i) {
deg[i] = 0; edge[i].clear();
}
for (int i = 1; i <= n; ++i) {
int u, v; cin >> u >> v;
edge[u].push_back(v);
edge[v].push_back(u);
++deg[u]; ++deg[v];
}
int cnt = 0;
for (int i = 1; i <= n; ++i)
if (deg[i] == 1) {
bfs[++cnt] = i;
--deg[i];
}
for (int i = 1; i <= cnt; ++i) {
int u = bfs[i];
for (auto v : edge[u]) {
--deg[v];
Union(u, v);
if (deg[v] == 1) {
bfs[++cnt] = v;
}
}
}
LL ans = n * (n - 1LL);
for (int i = 1; i <= n; ++i) {
if (is_root(i)) {
ans -= num[i] * (num[i] - 1LL) / 2;
}
}
cout << ans << endl;
}
signed main() {
int T; cin >> T;
while (T--) {
solve();
}
}
E. Number of Simple Paths(环基树 + 思维)
标签:int image inline 两种 signed fine roc return alt
原文地址:https://www.cnblogs.com/waryan/p/14038085.html