zoukankan      html  css  js  c++  java
  • tarjan

    学习资料:https://www.cnblogs.com/shadowland/p/5872257.html

    板子:

    void tarjan(int u){
        dfn[u]=low[u]=++cnt;
        sta[++top]=u;
        vis[u]=true;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
    if(!dfn[v]){ tarjan(v),low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ cmp[u]=++tot; vis[u]=false; int len=top; while(sta[top]!=u){ cmp[sta[top]]=tot; vis[sta[top--]]=false; } top--; sum[tot]=len-top;//缩点,记录该联通块的大小 } }

      

    例题:poj 2186 http://poj.org/problem?id=2186

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int M=1e4+5;
    vector<int>g[M];
    int out[M],cmp[M],dfn[M],low[M],sta[M],vis[M],sum[M],tot,cnt,top;
    void tarjan(int u){
        dfn[u]=low[u]=++cnt;
        sta[++top]=u;
        vis[u]=true;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(!dfn[v]){
                tarjan(v),low[u]=min(low[u],low[v]);
            }
            else if(vis[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]){
            cmp[u]=++tot;
            vis[u]=false;
            int len=top;
            while(sta[top]!=u){
                cmp[sta[top]]=tot;
                vis[sta[top--]]=false;
            }
            top--;
            sum[tot]=len-top;
        }
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        while(m--){
            int x,y;
            scanf("%d%d",&x,&y);
            g[x].push_back(y);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
        for(int i=1;i<=n;i++){
            for(int j=0;j<g[i].size();j++){
                int v=g[i][j];
                if(cmp[i]!=cmp[v])
                    out[cmp[i]]++;
            }
        }
        /*for(int i=1;i<=tot;i++)
            cout<<out[i]<<" ";
        cout<<endl;*/
        int s=0;
        for(int i=1;i<=tot;i++){
            if(!out[i]){
                if(s){
                    return puts("0"),0;
                }
                else
                    s=sum[i];
            }
        }
        printf("%d
    ",s);
        return 0;
    }
    View Code

    题目:poj1263

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    const int M=102;
    bool vis[M];
    vector<int>g[M];
    int cmp[M],dfn[M],low[M],sta[M],out[M],in[M];
    int n,m,cnt,tot,top;
    inline int read(){
        int summ=0,x=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                x=0;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
            summ=(summ<<1)+(summ<<3)+(ch^48),ch=getchar();
        return x?summ:-summ;
    }
    inline void write(int x){
        if(x<0)
            putchar('-'),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    void init(){
        tot=cnt=top=0;
        for(int i=0;i<=n;i++)
            g[i].clear(),sta[i]=0,cmp[i]=0,vis[i]=true,dfn[i]=0,in[i]=0,out[i]=0,low[i]=0;
        
    }
    void tarjan(int u){
        dfn[u]=low[u]=++cnt;
        sta[++top]=u;
        vis[u]=true;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(!dfn[v]){
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(vis[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]){
            cmp[u]=++tot;
            vis[u]=false;
            while(sta[top]!=u){
                cmp[sta[top]]=tot;
                vis[sta[top--]]=false;
            }
            top--;
        }
    } 
    int main(){
    
        while(~scanf("%d",&n)){
            
            init();
            for(int i=1;i<=n;i++){
                int x=read();
                while(x){
                    
                    g[i].push_back(x);
                    x=read();
                }
            }
            for(int i=1;i<=n;i++)
                if(!dfn[i])
                    tarjan(i);
            int countt=0,countt1=0;
            for(int i=1;i<=n;i++){
                for(int j=0;j<g[i].size();j++){
                    int v=g[i][j];
                    if(cmp[i]!=cmp[v])
                        out[cmp[i]]++,in[cmp[v]]++;
                }
            }
            //cout<<countt<<"~~"<<countt1<<endl;
            for(int i=1;i<=tot;i++){
                if(!in[i]){
                    countt++;
                }
                if(!out[i])
                    countt1++;
            }
            
            write(countt);
            putchar('
    ');
            if(tot==1)
                puts("0");
            else
                write(max(countt1,countt)),putchar('
    ');
        }
        
        return 0;
    }
    View Code

    题目:hud2767

    给定一张有向图,问最少添加几条边使得有向图成为一个强连通图。

    Tarjan入门经典题,用tarjan缩点,然后就变成一个有向无环图(DAG)了。 
    我们要考虑的问题是让它变成强连通,让DAG变成强连通就是把尾和头连起来,也就是入度和出度为0的点。 
    统计DAG入度和出度,然后计算头尾,最大的那个就是所求。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    inline int read(){
        int sum=0,x=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                x=0;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
            sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
        return x?sum:-sum;
    }
    inline void write(int x){
        if(x<0)
            putchar('-'),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    int mi(int x,int y){
        return x<y?x:y;
    }
    int ma(int x,int y){
        return x>y?x:y;
    }
    const int M=2e4+4;
    vector<int>g[M];
    int dfn[M],low[M],sta[M],cmp[M],in[M],out[M],n,m,top,tot,cnt;
    bool vis[M];
    void tarjan(int u){
        low[u]=dfn[u]=++cnt;
        sta[++top]=u;
        vis[u]=true;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(!dfn[v]){
                tarjan(v);
                low[u]=mi(low[u],low[v]);
            }
            else if(vis[v])
                low[u]=mi(low[u],dfn[v]);
        }
        if(low[u]==dfn[u]){
            cmp[u]=++tot;
            vis[u]=false;
            while(sta[top]!=u){
                cmp[sta[top]]=tot;
                vis[sta[top--]]=false;
            }
            top--;
        }
    }
    void init(){
        tot=top=cnt=0;
        for(int i=0;i<=n;i++)
            g[i].clear(),cmp[i]=0,low[i]=0,dfn[i]=0,out[i]=0,in[i]=0;
    }
    int main(){
        int t=read();
        while(t--){
            n=read(),m=read();
            /*if(m==0){
                write(n);
                putchar('
    ');
                continue;
            }*/
            init();
            while(m--){
                int x=read(),y=read();
                g[x].push_back(y);
            }
            for(int i=1;i<=n;i++)
                if(!dfn[i])
                    tarjan(i);
            if(tot==1){
                puts("0");
                continue;
            }
            for(int i=1;i<=n;i++)
                for(int j=0;j<g[i].size();j++){
                    int v=g[i][j];
                    if(cmp[i]!=cmp[v])
                        out[cmp[i]]++,in[cmp[v]]++;
                }
            int ans1=0,ans2=0;
            //cout<<"~~"<<tot<<endl;
            for(int i=1;i<=tot;i++){
                if(!out[i])
                    ans1++;
                if(!in[i])
                    ans2++;
            }
            write(ma(ans1,ans2));
            putchar('
    ');
        }
        return 0;
    }
    View Code

    题:poj2762

    题意·:给定图,问任意俩点x能否到达y(不需要俩俩可达)

    强联通+拓扑排序

    在sort过程中若入度为0的点数出现2次及2次以上则“no”

    详见:https://www.cnblogs.com/scau20110726/archive/2013/05/23/3094495.html

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const int M=10005;
    int in[M],out[M],sta[M],dfn[M],low[M],cmp[M],tot,top,cnt,n,m;
    bool vis[M];
    vector<int>g[M],newg[M];
    void tarjan(int u){
        low[u]=dfn[u]=++cnt;
        sta[++top]=u;
        vis[u]=true;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(!dfn[v]){
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(vis[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u]){
            cmp[u]=++tot;
            vis[u]=false;
            while(sta[top]!=u){
                cmp[sta[top]]=tot;
                vis[sta[top--]]=false;
            }
            top--;
        }
    }
    void init(){
        tot=top=cnt=0;
        for(int i=0;i<=n;i++)
            vis[i]=false,newg[i].clear(),g[i].clear(),sta[i]=0,in[i]=0,out[i]=0,dfn[i]=0,low[i]=0,cmp[i]=0;
    }
    void tuopu(){
        for(int i=1;i<=n;i++)
            for(int j=0;j<g[i].size();j++){
                int v=g[i][j];
                if(cmp[i]!=cmp[v])
                    out[cmp[i]]++,in[cmp[v]]++,newg[cmp[i]].push_back(cmp[v]);
            }
        queue<int>que;
        int ans=0;
        //vector<int>ans; 
        while(!que.empty())
            que.pop();
        for(int i=1;i<=tot;i++)
            if(!in[i])
                que.push(i),ans++;
        if(ans>1){
            puts("No");
            return ;
        }
        while(!que.empty()){
            int u=que.front();
            ans=0;
            que.pop();
            //ans.push_back(u);
            for(int i=0;i<newg[u].size();i++){
                int v=newg[u][i];
                in[v]--;
                if(!in[v]){
                    que.push(v);
                    ans++;
                }
            }
            if(ans>1){
                puts("No");
                return ;
            }
        }    
        //cout<<tot<<endl;
            puts("Yes");
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            init();
            while(m--){
                int x,y;
                scanf("%d%d",&x,&y);
                g[x].push_back(y);
            }
            for(int i=1;i<=n;i++)
                if(!dfn[i])
                    tarjan(i);
            tuopu();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    背包问题
    標準差、方差、正太分佈公式
    C#實現XML的增刪查改
    XML的基礎結構
    微信小程序入門學習資料鏈接
    微信小程序wxml無法實現頁面跳轉的問題
    088_jsp转成成servle所在的路径?
    075_jsp如何debug?
    028_Mybatis返回int类型为空时报错 attempted to return null from a method with a primitive return type (int)
    087_数据库类型
  • 原文地址:https://www.cnblogs.com/starve/p/10946166.html
Copyright © 2011-2022 走看看