因为最近在学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 }