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
原文地址:https://www.cnblogs.com/starve/p/10946166.html