1. 程式人生 > >圖論算法-Tarjan模板 【縮點;割頂;雙連通分量】

圖論算法-Tarjan模板 【縮點;割頂;雙連通分量】

else if false -m 例如 als for 算法思路 連通 tarjan

圖論算法-Tarjan模板 【縮點;割頂;雙連通分量】


為小夥伴們總結的Tarjan三大算法


Tarjan縮點(求強連通分量)

int n;
int low[100010],dfn[100010];
bool ins[100010];
int col[100010];//記錄每個點所屬強連通分量(即染色)
vector<int> map[100010];
stack<int> st;
int tot;//時間戳
int colnum;//記錄強連通分量個數

void tarjan(int u)
{
    low[u]=dfn[u]=++tot;
    st.push(u);
    ins[u]=true;

    for(int j=0;j<map[u].size();j++)
    {
        int v=map[u][j];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        
        else if(ins[v])
        low[u]=min(low[u],dfn[v]);
    }
    
    if(low[u]==dfn[u])
    {
        //到這裏即發現了一個新的強連通分量
        colnum++;
        
        int temp;
        int cont=0;
        do
        {
            temp=st.top();
            st.pop();
            ins[temp]=false;
            
            //將同一強連通分量的點染色,表示一個縮點
            col[temp]=colnum;
            
            //在這裏也可以對該強連通分量進行一些其他操作
            //例如保存該縮點所包含的原節點
        }
        while(temp!=u);
    }
}

void init()
{
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(col,0,sizeof(col));
    memset(ins,false,sizeof(ins));
    tot=colnum=0;
}

void solve()
{
    init();
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
        tarjan(i);
    }
}

Tarjan求割點(割頂)

int n;
vector<int> map[100010];
int low[100010],dfn[100010];
bool cut[1000010];//記錄割點
int tot;

void tarjan(int u,int fa)
{
    low[u]=dfn[u]=++tot;
    int child=0;
    for(int j=0;j<map[u].size();j++)
    {
        int v=map[u][j];
        if(!dfn[v])
        {
            child++;
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            
            if(low[v]>=dfn[u])
            cut[u]=true;
        }
        
        else if(dfn[v]<dfn[u]&&v!=fa)
        low[u]=min(low[u],dfn[v]);
    }
    
    if(fa<0&&child==1)
    cut[u]=false;
}

void init()
{
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(cut,false,sizeof(cut));
    tot=0;
}

void solve()
{
    
    init();
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
        tarjan(i,-1);
        //**高亮**這裏的第二個參數一定要設為負數
    }
    //cut[i]==true即表示i為割點
}

Tarjan求點-雙連通分量

int n;
vector<int> map[100010];
int low[100010],dfn[100010];
bool cut[1000010];
int bcc[1000010];
int tot;
int bcc_cont//記錄雙連通分量個數;
struct edge{int u,v};
stack<edge> E;

void tarjan(int u,int fa)
{
    low[u]=dfn[u]=++tot;
    int child=0;
    for(int j=0;j<map[u].size();j++)
    {
        int v=map[u][j];
        edge e=(edge) {u,v};
        
        if(!dfn[v])
        {
            E.push(e);
            child++;
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            
            if(low[v]>=dfn[u])
            {
                //到這裏即發現了一個新的雙連通分量
                cut[u]=true;
                bcc_cont++:
                
                while(1)
                {
                    edge temp=E.top();
                    E.pop();
                    
                    if(bccno[temp.u]!=bcc_cont)
                    bccno[temp.u]=bcc_cont;
                    if(bccno[temp.v]!=bcc_cont)
                    bccno[temp.v]=bcc_cont;
                    
                    if(temp.u==u&&temp.v==v)
                    break;
                }   
            }
        }
        
        else if(dfn[v]<dfn[u]&&v!=fa)
        {
            E.push(e);
            low[u]=min(low[u],dfn[v]);
        }
    }
    
    if(fa<0&&child==1)
    cut[u]=false;
}

void init()
{
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(bccno,0,sizeof(bccno));
    tot=bcc_cont=0;
}

void solve()
{
    
    init();
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
        tarjan(i,-1);//**高亮**這裏的第二個參數一定要設為負數
    }
}

其實三個算法思路都基本一致
畢竟都是同一個人提出的嘛

圖論算法-Tarjan模板 【縮點;割頂;雙連通分量】