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\n",ans); 87 } 88 else 89 printf("0\n"); 90 return 0; 91 }