Counting Cycles Aizu - 1388 虚树 模板题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lifelikes/article/details/83217878

点我看题

题意 给出一个图 ,问其中有多少个简单环。
边数最多比点数多15

解题思路
边数最多比点数多15。 这是一个很经典的条件。 1.想到状压枚举,2.想到建出生成树,然后暴力加边。

思考枚举边的时候如何判断是否有环。
这是一个图论小技巧,将选出来的边的端点 往上异或边异或到根节点, 异或完成后,所有值等于1的边就是应该要选的边。
然后暴力判断这些边是否能构成一个简单环即可。 但这样 复杂度会是O(n*size(E)) 。
然后用虚树优化一下就可以了。 这样 复杂度就很低了。
整个的复杂度就变成了构建虚树的复杂度。 已经非常优秀的算法了。
自己整理了一个虚数的板子 感觉还是很有趣的。

#include <bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int MAX = 1e5+30;
class Edge {
public:
    int u,v,next,w;
};
class GRAPH {
public:
    int tot;
    int head[MAX];
    Edge edge[MAX<<1];
    void init() {
        memset(head,-1,sizeof head);
        tot=0;
    }
    void add(int u,int v,int w) {
        edge[tot].u=u,edge[tot].v=v;
        edge[tot].next=head[u];
        edge[tot].w=w;
        head[u]=tot;
        tot++;
    }
};
GRAPH t_tree;
int id[MAX];
bool cmp(int &i,int &j) {
    return id[i]<id[j];
}
class VTREE {
public:
    vector<int> node;
    int n;
    int root;
    GRAPH v_tree;
    void init(int _root,int _n,vector<int> &_node) { //树根 原树的大小,关键点
        v_tree.init();
        root = _root;
        n=_n;
        node=_node;
    }
    bool vis[MAX];
    int indx;
    int fa[MAX][20],dep[MAX];
    void dfs(int u) {
        vis[u]=1,id[u]=++indx;
        for(int i=t_tree.head[u]; i!=-1; i=t_tree.edge[i].next) {
            int v= t_tree.edge[i].v;
            if(vis[v])
                continue;
            fa[v][0]=u;
            dep[v]=dep[u]+1;
            dfs(v);
        }
    }
    void prelca() {
        indx=0;
        dfs(root);
        for(int j = 1; j<20; j++) {
            for(int i=1; i<=n; i++) {
                fa[i][j]=fa[fa[i][j-1]][j-1];
            }
        }
    }
    int lca(int u,int v) {
        if(dep[u]<dep[v])
            swap(u,v);
        for(int k=dep[u]-dep[v],j=0; k; j++,k>>=1) {
            if(k&1)
                u = fa[u][j];
        }
        if(u==v)
            return u;
        for(int j=19; j>=0; j--) {
            if(fa[u][j]!=fa[v][j])
                u  =fa[u][j],v=fa[v][j];
        }
        return fa[u][0];
    }
    int top,stk[MAX],key[MAX];
    void build() {
        prelca();
        memset(key,0,sizeof key);
        int tops=node.size();
        //cout<<"tops:"<<tops<<endl;
        sort(node.begin(),node.end(),cmp);
        for(int i=0; i<tops; i++) {
            key[node[i]]=1;
        }
        for(int i=0; i<tops; i++) {
            //cout<<node[i]<<"<,>id:"<<id[node[i]]<<endl;
            int x = node[i];
            if(!top) {
                stk[++top] = x;
                continue;
            }
            int plca = lca(stk[top],x);
            while(dep[stk[top-1]]>dep[plca] && top>1) {
                v_tree.add(stk[top-1],stk[top],0);
                top--;
            }
            if(dep[plca]< dep[stk[top]]) {
                v_tree.add(plca,stk[top],0);
                top--;
            }
            if(!top || dep[stk[top]]<dep[plca])
                stk[++top]=plca;
            stk[++top] = x;
            if(!key[plca]) {
                key[plca]=1;
                node.push_back(plca);
            }
        }
        while(top>1) {
            if(stk[top-1]!=stk[top])
                v_tree.add(stk[top-1],stk[top],0);
            top--;
        }
    }
};
VTREE vtree;
vector<pair<int,int> > nE;
vector<int> nN;
int dsu[MAX];
int finds(int x) {
    if(dsu[x]==x)
        return x;
    return dsu[x]=finds(dsu[x]);
}
int vis[MAX];
int fa[MAX];
void getfa(int u,int pre) {
    fa[u]=pre;
    for(int i=vtree.v_tree.head[u]; i!=-1; i=vtree.v_tree.edge[i].next) {
        int v=vtree.v_tree.edge[i].v;
        if(v==pre)
            continue;
        getfa(v,u);
    }
}
void slove(int u,int c) {
    while(u!=-1) {
        if(vis[u])
            vis[u]=0;
        else
            vis[u]=c;
        u=fa[u];
    }
}
int checks[MAX];
vector<int> G[MAX];
int num;
int du[MAX];
bool dfs(int u,int pre){
    if(checks[u]) return 0;
    checks[u]=1;
    num++;
    for(int i=0;i<G[u].size();i++){
        if(G[u][i]==pre) continue;
        if(dfs(G[u][i],u)){
            continue;
        }else{
            return 0;
        }
    }
    return 1;
}
int main() {
    t_tree.init();
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=0; i<=n; i++) {
        dsu[i]=i;
    }
    for(int i=0; i<m; i++) {
        int u,v;
        scanf("%d %d",&u,&v);
        int x=finds(u),y=finds(v);
        if(x==y) {
            nN.push_back(v);
            nN.push_back(u);
            nE.push_back(make_pair(u,v));
        } else {
            t_tree.add(u,v,0);
            t_tree.add(v,u,0);
            dsu[x]=y;
        }
    }
    sort(nN.begin(),nN.end());
    nN.push_back(1);
    nN.erase(unique(nN.begin(),nN.end()),nN.end());
    vtree.init(1,n,nN);
    vtree.build();
    getfa(1,-1);
    int top=(1<<nE.size());
    int ans = 0;
    vector<int> cnt;
    for(int i=1; i<top; i++) {
        for(int j=0;j<vtree.node.size();j++){
            int v= vtree.node[j];
            checks[v]=vis[v]=du[v]=0;
            G[v].clear();
        }
        cnt.clear();
        vector<pair<int,int> > P;
        vector<int> counts;
        for(int j=0; j<nE.size(); j++) {
            if((1<<j)&i){
                slove(nE[j].first,i);
                slove(nE[j].second,i);
                G[nE[j].first].push_back(nE[j].second);
                G[nE[j].second].push_back(nE[j].first);
                du[nE[j].first]++;
                du[nE[j].second]++;
                P.push_back(make_pair(nE[j].second,nE[j].first));
                counts.push_back(nE[j].second);
                counts.push_back(nE[j].first);
            }
        }

        for(int j=0;j<vtree.node.size();j++){
            int v= vtree.node[j];
            if(vis[v]==i){
                G[fa[v]].push_back(v);
                G[v].push_back(fa[v]);
                du[fa[v]]++;
                du[v]++;
                P.push_back(make_pair(v,fa[v]));
                counts.push_back(v);
                counts.push_back(fa[v]);
            }
        }
        sort(counts.begin(),counts.end());
        counts.erase(unique(counts.begin(),counts.end()),counts.end());
        int ok=1;
        for(int i=0;i<P.size();i++){
            if(du[P[i].first]!=2 || du[P[i].second]!=2){
                ok=0;
            }
        }
        num=0;
        dfs(P[0].first,-1);
        if(num!=counts.size()){
            ok=0;
        }
        if(P.size()==0) ok=0;
        if(ok) ans++;
    }
    cout<<ans<<endl;
    return 0;
}
//1 2
//2 4
//4 8
//4 9
//2 5
//5 10
//5 11
//1 3
//3 6
//6 12
//6 13
//3 7
//7 14
//11 12
//5 6

猜你喜欢

转载自blog.csdn.net/lifelikes/article/details/83217878