• 图论三


    0、目录

    无向图割顶和桥、无向图双连通分量、有向图强连通分量、TwoSAT、并查集、拓扑排序、黑白染色、欧拉图、表达式树
    (参考自白皮)

    1、无向图割顶和桥

    int pre[maxn],low[maxn],iscut[maxn],dfs_clock;
    //int isbrige[maxm];
    
    int dfs(int u,int fa){
        int lowu=pre[u]=++dfs_clock;
        int child=0;
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!pre[v]){
                child++;
                int lowv=dfs(v,u);
                lowu=min(lowu,lowv);
                if(lowv>=pre[u]){
                    iscut[u]=true;
                }
    //            if(lowv>pre[u]){
    //                isbridge[e]=true;
    //            }
            }else if(pre[v]<pre[u]&&v!=fa){
                lowu=min(lowu,pre[v]);
            }
        }
        if(fa<0&&child==1) iscut[u]=0;
        low[u]=lowu;
        return lowu;
    }
    

    2、无向图双连通分量

    2.1、点双联通

    int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;
    vector<int> G[maxn],bcc[maxn];
    
    stack<Edge> S;
    
    int dfs(int u,int fa){
        int lowu=pre[u]=++dfs_clock;
        int child=0;
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            Edge& e=Edge(u,v);
            if(!pre[v]){
                S.push(e);
                child++;
                int lowv=dfs(v,u);
                lowu=min(lowu,lowv);
                if(lowv>=pre[u]){
                    iscut[u]=true;
                    bcc_cnt++; bcc[bcc_cnt].clear();
                    for(;;){
                        Edge& x=S.top(); S.pop();
                        if(bccno[x.u]!=bcc_cnt){
                            bcc[bcc_cnt].push_back(x.u);
                            bccno[x.u]=bcc_cnt;
                        }
                        if(bccno[x.v]!=bcc_cnt){
                            bcc[bcc_cnt].push_back(x.v);
                            bccno[x.v]=bcc_cnt;
                        }
                        if(x.u==u&&x.v==v) break;
                    }
                }
            }else if(pre[v]<pre[u]&&v!=fa){
                S..push(e);
                lowu=min(lowu,pre[v]);
            }
        }
        if(fa<0&&child==1) iscut[u]=0;
        return lowu;
    }
    
    void find_bcc(int n){
        memset(pre,0,sizeof(pre));
        memset(iscut,0,sizeof(iscut));
        memset(bccno,0,sizeof(bccno));
        dfs_clock=bcc_cnt=0;
        for(int i=0;i<n;i++){
            if(!pre[i]) dfs(i,-1);
        }
    }
    

    2.2、边双连通

    2.2.1、把桥都删了,剩下的连通分量就是边双连通

    2.2.2、用有向图强连通分量来处理

    3、有向图强连通分量

    3.1、两次dfs

    vector<int> G[maxn],G2[maxn];
    vector<int> S;
    int vis[maxn],sccno[maxn],scc_cnt;
    
    void dfs1(int u){
        if(vis[u]) return ;
        vis[u]=1;
        for(int i=0;i<G[u].size();i++) dfs1(G[u][i]);
        S.push_back(u);
    }
    
    void dfs2(int u){
        if(sccno[u]) return;
        sccno[u]=scc_cnt;
        for(int i=0;i<G2[u].size();i++) dfs2(G2[u][i]);
    }
    
    void find_scc(int n){
        scc_cnt=0;
        S.clear();
        memset(sccno,0,sizeof(sccno));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++) dfs1(i);
        for(int i=n-1;i>=0;i--)
            if(!sccno[S[i]]){ scc_cnt++; dfs2(S[i]); }
    }
    

    3.2、tarjan

    vector<int> G[maxn];
    int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
    stack<int> S;
    
    void dfs(int u){
        pre[u]=lowlink[u]=++dfs_clock;
        S.push(u);
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!pre[v]){
                dfs(v);
                lowlink[u]=min(lowlink[u],lowlink[v]);
            }else if(!sccno[v]){
                lowlink[u]=min(lowlink[u],pre[v]);
            }
        }
        if(lowlink[u]==pre[u]){
            scc_cnt++;
            for(;;){
                int x=S.top(); S.pop();
                sccno[x]=scc_cnt;
                if(x==u) break;
            }
        }
    }
    
    void find_scc(int n){
        dfs_clock=scc_cnt=0;
        memset(sccno,0,sizeof(sccno));
        memset(pre,0,sizeof(pre));
        for(int i=0;i<n;i++) if(!pre[i]) dfs(i);
    }
    

    4、TowSAT

    struct TwoSAT{
        int n;
        vector<int> G[maxn*2];
        bool mark[maxn*2];
        int S[maxn*2],c;
    
        bool dfs(int x){
            if(mark[x^1]) return false;
            if(mark[x]) return true;
            mark[x]=true;
            S[c++]=x;
            for(int i=0;i<G[x].size();i++)
                if(!dfs(G[x][i])) return false;
            return true;
        }
    
        void init(int n){
            this->n=n;
            for(int i=0;i<n*2;i++) G[i].clear();
            memset(mark,0,sizeof(mark));
        }
    
        void add_clause(int x,int xval,int y,int yval){
            x=x*2+xval;
            y=y*2+yval;
            G[x^1].push_back(y);
            G[y^1].push_back(x);
        }
    
        bool solve(){
            for(int i=0;i<n*2;i+=2){
                if(!mark[i]&&!mark[i+1]){
                    c=0;
                    if(!dfs(i)){
                        while(c>0) mark[S[--c]]=false;
                        if(!dfs(i+1)) return false;
                    }
                }
            }
            return true;
        }
    }
    

    5、并查集

    int fa[maxn];
    
    int find(int x){
        return fa[x]=fa[x]==x?x:find(fa[x]);
    }
    
    int Union(int u,int v){
        int pu=find(u);
        int pv=find(v);
        if(pu!=pv){
            fa[pv]=pu;
        }
    }
    

    6、拓扑排序

    queue<int> Q;
    for(int i=0;i<n;i++){
        if(!ind[i]) Q.push(i);
    }
    
    while(!Q.empty()){
        int u=Q.front(); Q.pop();
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            ind[v]--;
            if(!ind[v]){
                Q.push(v);
            }
        }
    }
    

    7、黑白染色

    int color[maxn];
    bool dfs(int u){
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(color[v]==color[u]) return false;
            if(!color[v]){
                color[v]=3-color[u];
                if(!dfs(v)) return false;
            }
        }
    }
    

    8、欧拉路

    8.1、无向图欧拉回路构造

    int vis[maxm];
    vector<int> path;
    void euler(int u){
        for(int i=0;i<G[u].size();i++){
            int id=G[u][i];
            Edge& e=egs[id];
            if(!vis[id]){
                vis[id]=vis[id^1]=1;
                euler(e.v);
                path.push_back(e.v);
            }
        }
    }
  • 相关阅读:
    常用/常见Java Web 服务器/应用服务器Logo图文介绍
    三个快速且简单的让你的大脑安静下来的方法
    怎样判断自己是否在程序员平庸者之列?
    “好奇号”火星车和它搭载的软件(来自Erlang程序员的观点)
    旁观者效应”是如何毁掉我们的代码的
    怎么理解面向对象和面向过程到底的本质区别?
    面向对象方法论与结构化方法论的本质区别【转】
    不懂技术的人不要对懂技术的人说这很容易实现
    最近,波兰的程序员Chris(也叫KreCi)公布了他的第十四期程序员收入报告
    计算机专业的学生必须掌握的五门课程 不能掌握他们就不应该获得学位
  • 原文地址:https://www.cnblogs.com/fenice/p/5852258.html
Copyright © 2020-2023  润新知