zoukankan      html  css  js  c++  java
  • [学习笔记]Tarjan&&欧拉回路

    本篇并不适合初学者阅读。

    SCC:

    1.Tarjan缩点:x回溯前,dfn[x]==low[x]则缩点。

    注意:

    ①sta,in[]标记。

    ②缩点之后连边可能有重边。

    2.应用:

    SCC应用范围还是很广的。

    基本思路是:Tarjan+topo

    DAG是个好东西。

    各种判断连通性(传递关系),计数,以及dp转移

    感觉90%以上的tarjan都是考SCC

    例题:最大半连通子图(这个题注意缩点后的重边)

    衍生应用算法:

    ①2-SAT

    ②完备匹配的二分图必须边和可行边。

    E-DCC

    1.Tarjan找桥:x的一个子节点y,dfn[x]<low[y],边就是桥

    注意:

    ①in_edge,对称建边号。不能从in_edge^1出发。但是可以走重边。

    然后不经过桥dfs,找E-DCC

    2.应用:

    ①最短路的必经边:建出最短路图,找桥即可。

    ②例题:poj3694

    找出桥边,E-DCC缩点。

    对于询问(x,y)x,y不在一个DCC,

    找LCA,之后可以往上暴力找路径,干掉桥。

    然鹅使用并查集更快。

    O(M+N+Qlogn)

    V-DCC

    1.找割点:dfn[x]<=low[y]不用管重边什么的。

    注意:

    ①搜索树根节点要有两次符合,才是割点。

    其实对于割点x,dfn[x]<=low[y]的出点y,这些y一定在不同的DCC中。

    缩点:

    除了孤立点之外,每个DCC大小至少为2


    每个割点属于多个DCC

    用栈维护。

    如果某个点满足dfn[x]<=low[y]

    那么,不断弹出栈顶,直到y弹出。

    把这些点和x都放进一个DCC中。(vector存)

    可以发现一个x属于多个DCC

    缩点的时候,

    先把割点设置编号(cnt+1~cnt+tot)cnt是DCC个数

    tot是割点个数

    循环所有的DCC,循环所有的成员

    如果找到割点,就让这个割点和这个DCC连边。

    连出一个黑点白点相间的树(黑点可以认为是割点)

    例题:

    [HNOI2012]矿场搭建

    分类讨论即可

    KNIGHTS - Knights of the Round Table

    性质题,

    建立反图。没有仇恨的人连边。

    没有出现在任何一个简单奇环中的骑士滚蛋

    V-DCC缩点

    如果两个骑士DCC不同,一定不能同时出席。(否则在一个奇环中的话,那么两个DCC可以合并。矛盾)

    如果一个DCC中有奇环,那么DCC中的所有骑士都可以被一个奇环包含。(可以构造)

    综上,一个骑士被包含,因为不能和其他DCC合作,所以必须当且仅当自己的DCC中有奇环

    Tarjan+二分图染色判断奇环

    代码:

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    namespace Miracle{
    const int N=1005;
    const int M=1e6+5;
    bool hate[N][N];
    int n,m;
    void rd(int &x){
        char ch;x=0;
        while(!isdigit(ch=getchar()));
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    }
    struct node{
        int nxt,to;
    }e[2*M];
    int cnt,hd[N];
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    bool cut[N];
    bool has[N];//for cut
    vector<int>mem[N];
    int rt;
    int be[N];
    int sta[N],top;
    int dfn[N],low[N];
    int df;
    int dcc;
    void tarjan(int x){
        sta[++top]=x;
        low[x]=dfn[x]=++df;
        bool fl=false;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
                if(dfn[x]<=low[y]){
                    ++dcc;
                    mem[dcc].clear();
                    if(fl||x!=rt) cut[x]=1;
                    fl=true;
                    int z;
                    do{
                        z=sta[top--];
                        be[z]=dcc;
                        mem[dcc].push_back(z);
                    }while(z!=y);
                    be[x]=dcc;
                    mem[dcc].push_back(x);
                }
            }
            else low[x]=min(low[x],dfn[y]);
        }
    }
    int c[N];
    bool bla;
    bool ok[N];
    void che(int x,int las,int id){
    //    cout<<" che "<<x<<endl;
        c[x]=las;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            
            if(be[y]!=id) continue;
        //    cout<<" goto "<<y<<endl;
            if(!c[y]){
                che(y,3-las,id);
            }
            else if(c[y]==c[x]) bla=false;
            //if(!fl) return false;
        }
        //return fl;
    }
    void clear(){
        memset(hate,0,sizeof hate);
        memset(cut,0,sizeof cut);
        memset(hd,0,sizeof hd);cnt=0;
        memset(dfn,0,sizeof dfn);df=0;
        memset(ok,0,sizeof ok);
        dcc=0;
        memset(c,0,sizeof c);
        memset(has,0,sizeof has);
        memset(be,0,sizeof be);
    }
    int main(){
        while(1)
        {
            scanf("%d%d",&n,&m);int x,y;
            if(n==0&&m==0) break;
            clear();
            for(reg i=1;i<=m;++i){
                rd(x);rd(y);
                hate[x][y]=1;
            }
            for(reg i=1;i<=n;++i){
                for(reg j=i+1;j<=n;++j){
                    if(!hate[i][j]){
                        add(i,j);add(j,i);
                    }
                }
            }
            for(reg i=1;i<=n;++i){
                if(!dfn[i]) rt=i,top=0,tarjan(i);
            }
    //        cout<<" dcc "<<dcc<<endl;
    //        for(int i=1;i<=n;++i){
    //            cout<<i<<" : "<<cut[i]<<" "<<be[i]<<endl;
    //        }cout<<endl;
            for(reg i=1;i<=dcc;++i){
            //    cout<<" i---------- "<<i<<endl;
                memset(c,0,sizeof c);
                for(reg j=0;j<mem[i].size();++j){
            //        cout<<" mem "<<mem[i][j]<<endl;
                        be[mem[i][j]]=i;
                }
                bla=true;
                che(mem[i][0],1,i);
            //    cout<<" bla "<<bla<<endl;
                if(!bla){
                    for(reg j=0;j<mem[i].size();++j){
                        ok[mem[i][j]]=1;
                    }
                }
            }
            
            int ans=n;
            for(reg i=1;i<=n;++i){
                ans-=ok[i];
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    }
    int main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2018/11/6 7:40:18
    */
    View Code

    附赠福利:

    欧拉回路:

    void dfs(int x){

    for(each son)
    if(!vis[i]){

    vis[i]=vis[i^1]=1;

    dfs(e[i].to)
    }

    sta[++top]=x;

    }

    然后sta倒着输出即可。

    至于每个点访问多次,可以弧优化减少枚举。

  • 相关阅读:
    remove white space from read
    optimize the access speed of django website
    dowload image from requests
    run jupyter from command
    crawl wechat page
    python version 2.7 required which was not found in the registry windows 7
    health
    alternate rows shading using conditional formatting
    word
    【JAVA基础】static 关键字
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9911695.html
Copyright © 2011-2022 走看看