E. Nombre de chemins simples (pensée inverse + arbre de l'anneau de base)

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


Référence: https://frozenguardian.blog.csdn.net/article/details/110137634?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant BlogCommendFromMachineLearnPai2-1.control

L'idée principale du sujet: étant donné un arbre de base avec n points, le nombre de chemins de longueur supérieure ou égale à 1.

Idée: Pour tous les chemins (x, y) peuvent être divisés dans les deux cas suivants à considérer:

  1. Le chemin ne passe pas par les arêtes de l'anneau: le chemin entre le point x et le point y est unique
  2. Le chemin passera par les bords de l'anneau: à ce moment, il y a deux chemins entre le point x et le point y, l'un va dans le sens des aiguilles d'une montre le long de l'anneau et l'autre dans le sens inverse des aiguilles d'une montre le long de l'anneau

Le contraire est vrai. Tout d'abord, supposons que tous les chemins traverseront les arêtes de l'anneau, puis compter le nombre de paires de points (x, y) entre les chemins qui n'ont pas besoin de passer par les arêtes de l'anneau et de soustraire leur contribution.

(Chaque point et ses points restants seront comptés comme un de plus)

L'implémentation spécifique consiste à sortir de l'anneau en premier. Cela peut être exécuté à l'aide de la topologie ou de dfs, puis traiter l'anneau entier comme le nœud racine, de sorte que le graphe entier puisse être considéré comme une arborescence et être à court de tous les enfants. avec l'anneau comme nœud "racine" La taille de l'arbre est suffisante, car chaque sous-arbre est indépendant l'un de l'autre, et il ne doit y avoir qu'un seul chemin entre deux points dans chaque sous-arbre.


#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+100;
typedef long long LL;
bool loop[maxn],vis[maxn];
LL fa[maxn],dfn[maxn],id;
vector<LL>g[maxn];
void init(LL n){
    id=0;
    for(LL i=0;i<n+10;i++){
        g[i].clear();
        vis[i]=loop[i]=0;
        fa[i]=dfn[i]=0;
    }
}
void get_loop(LL u){
    dfn[u]=++id;
    for(LL i=0;i<g[u].size();i++){
        LL v=g[u][i];
        if(dfn[v]){
            if(dfn[v]<dfn[u]) continue;
            while(v!=fa[u]){
                loop[v]=true;
                v=fa[v];
            }
        }
        else{
            fa[v]=u;
            get_loop(v);
        }
    }
}
LL dfs(LL u){
    vis[u]=true;
    LL ans=1;
    for(LL i=0;i<g[u].size();i++){
        LL v=g[u][i];
        if(vis[v]||loop[v]) continue;
        ans+=dfs(v);
    }
    return ans;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL t;cin>>t;
  while(t--){
    LL n;cin>>n;
    init(n);
    for(LL i=1;i<=n;i++){
        LL u,v;cin>>u>>v;
        g[u].push_back(v);g[v].push_back(u);
    }
    get_loop(1);
    LL ans=n*(n-1);
    for(LL i=1;i<=n;i++){
        if(loop[i]){
            LL k=dfs(i);///带上了基环点
            k=max(k,(LL)0);
            ans-=k*(k-1)/2;
        }
    }
    cout<<ans<<endl;
  }
return 0;
}

 

Je suppose que tu aimes

Origine blog.csdn.net/zstuyyyyccccbbbb/article/details/113092029
conseillé
Classement