CodeForce 1454 E. Number of Simple Paths

题目链接

https://codeforces.com/contest/1454/problem/E

题意

给定(n)个顶点,(n)条边, 问这张图上有多少条无向的简单路径。

思路

(n)条边的话,就是一棵树加一条边,简称基环树。
一棵树上的简单路径条数是(C_{n}^{2}), 加了一条边之后, 假设之前所有路径都经过这条边, 那么共有 (C_{n}^{2} * 2) 种路径。
很明显这样会多算,那么我们发现不经过环上的任意点的俩点间的简单路径不会经过这条边, 因此把多余部分减去即可。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 50;
ll num[maxn], far[maxn];
int du[maxn], bfs[maxn];
vector<int> G[maxn];
int find(int x){
    if(far[x] == x) return x;
    else return far[x] = find(far[x]);
}
void unite(int x, int y){
    x = find(x);
    y = find(y);
    if(x == y) return ;
    far[x] = y;
    num[y] += num[x];
}
void init(int n){
    for(int i = 1;i <= n;i++){
        far[i] = i;
        num[i] = 1;
        du[i] = 0;
        G[i].clear();
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        init(n);
        for(int i = 1;i <= n;i++){
            int u, v;
            cin >> u >> v;
            G[u].push_back(v);
            G[v].push_back(u);
            du[u]++, du[v]++;
        }
        int cnt = 0;
        for(int i = 1;i <= n;i++){
            if(du[i] == 1){
                bfs[++cnt] = i;
                du[i]--;
            }
        }
        for(int i = 1;i <= cnt;i++){
            int u = bfs[i];
            for(auto v : G[u]){
                --du[v];
                unite(v, u);
                if(du[v] == 1){
                    bfs[++cnt] = v;
                }
            }
        }
        ll ans = n * (n - 1LL);
        for(int i = 1;i <= n;i++){
            if(far[i] == i){
                ans -= num[i] * (num[i] - 1LL) / 2;
            }
        }
        cout << ans << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Carered/p/14043680.html