1. 程式人生 > 實用技巧 >CF1454 E. Number of Simple Paths

CF1454 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;
}