Tarjan算法(缩点)

因为最近在学2sat,需要学习前置技能—Tarjan算法,所以花了一天的时间学习这个算法

算法步骤:

1.从一个点开始dfs,并加入栈

2.如果下一个点没有到过,跳到第一步

3.如果下一个点到过,并且在栈中,下一个点到这个点,这一段构成一个回路,也就是可以缩点

具体实现

void dfs(int x)
{
    st.push(x);      //加入栈
    dis[x]=1;        //x点在栈中
    dfn[x]=low[x]=++te;    //dfn用来表示某个点访问过,并且记录初始的low值
    for(int i=f[x]; i; i=nex[i])
    {
        int v=to[i];
        if(dfn[v]==0)
        {
            dfs(v);
            low[x]=min(low[x],low[v]);   //将一个回路的low改成一样的
        }
        else if(dis[v]==1)low[x]=min(low[x],low[v]);    //下一个点在栈中,那么找到一个回路,但是可能是嵌套回路,所以取最小low
    }
    if(dfn[x]==low[x])   //表示x点的初始值没有被改变,构成一个强连通分量
    { 
        while(st.size())
        {
            int g=st.top();
            st.pop();
            dis[g]=0;
            id[g]=x;    //用x命名强连通分量
            if(g==x)break;  //代表g是强连通分量的最后一个数
        }
    }
}

题目:poj2186

题解:先缩点,然后构成一个新的图,找到出度为一的一个被缩过的点,返回这个点的数量,如果有1个以上被缩过的点出度为0,那么返回0

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <ctime>
 5 #include <cstdlib>
 6 #include <vector>
 7 #include <stack>
 8 using namespace std;
 9 #define ll long long
10 const int maxn=1e4+10;
11 const int maxm=5e4+10;
12 int f[maxn],nex[maxm],to[maxm],cnt,ot[maxm];
13 int dfn[maxn],low[maxn],id[maxn],te;
14 vector<int>ve;
15 stack<int>st;
16 int ma[maxn];
17 bool dis[maxn];
18 void add(int a,int b)
19 {
20     cnt++;
21     to[cnt]=b;
22     nex[cnt]=f[a];
23     f[a]=cnt;
24     ot[cnt]=a;
25 }
26 void dfs(int x)
27 {
28     st.push(x);
29     dis[x]=1;
30     dfn[x]=low[x]=++te;
31     for(int i=f[x]; i; i=nex[i])
32     {
33         int v=to[i];
34         if(dfn[v]==0)
35         {
36             dfs(v);
37             low[x]=min(low[x],low[v]);
38         }
39         else if(dis[v]==1)low[x]=min(low[x],low[v]);
40     }
41     if(dfn[x]==low[x])
42     {
43         ve.push_back(x);
44         while(st.size())
45         {
46             int g=st.top();
47             st.pop();
48             dis[g]=0;
49             id[g]=x;
50             if(g==x)break;
51         }
52     }
53 }
54 int main()
55 {
56     int n,m;
57     scanf("%d %d",&n,&m);
58     for(int i=1; i<=n; i++)id[i]=i;
59     for(int i=1; i<=m; i++)
60     {
61         int a,b;
62         scanf("%d %d",&a,&b);
63         add(a,b);
64     }
65     for(int i=1; i<=n; i++)
66         if(dfn[i]==0)dfs(i);
67     for(int i=1; i<=cnt; i++)
68     {
69         int a=id[to[i]];
70         int b=id[ot[i]];
71         if(a!=b)
72             ma[b]++;
73     }
74     int fla=0,num=0;
75 
76     for(int i=0; i<ve.size(); i++)
77     {
78         if(ma[ve[i]]==0)num++,fla=ve[i];
79     }
80     if(ve.size()==1)num=1,fla=ve[0];
81     if(num==1)
82     {
83         int ans=0;
84         for(int i=1; i<=n; i++)
85             if(id[i]==fla)ans++;
86         printf("%d
",ans);
87     }
88     else
89         printf("0
");
90     return 0;
91 }
原文地址:https://www.cnblogs.com/carcar/p/9733200.html