【HDU 3594 Cactus】tarjan+仙人掌图

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3594

题目大意:给你一个图,让你判断他是不是仙人掌图。

仙人掌图的条件是:

1、是强连通图。

2、每条边在仙人掌图中只属于一个强连通分量。

仙人掌图介绍   -->  https://files.cnblogs.com/ambition/cactus_solution.pdf

解题思路:

1、首先得先熟练掌握塔尖tarjan算法的应用。

2、必须了解仙人掌图的三个性质:

(1).仙人掌dfs图中不能有横向边,简单的理解为每个点只能出现在一个强联通分量中。

(2).low[v]<dfn[u],其中u为v的父节点

(3).a[u]+b[u]<2 ,  a[u]为u节点的儿子节点中有a[u]个low值小于u的dfn值。b[u]为u的逆向边条数。

三个性质有一个不满足则不是仙人掌图。

 1 #include <algorithm>
 2 #include <vector>
 3 #include <iostream>
 4 #include <cstdio>
 5 #include <cstring>
 6 using namespace std;
 7 
 8 const int maxn=20005;
 9 int  dfn[maxn], low[maxn], stack[maxn], belong[maxn];
10 bool instack[maxn], color[maxn], ok;
11 int top, scnt, Index, n;
12 vector<int>vt[maxn];
13 
14 void Init_tarjan()
15 {
16     top=scnt=Index=0;
17     for(int i=1; i<=n; i++) dfn[i]=low[i]=instack[i]=color[i]=0;
18 }
19 
20 void tarjan(int u)
21 {
22     stack[++top]=u;
23     dfn[u]=low[u]=++Index;
24     instack[u]=1;
25     int cnt=0;
26     for(int i=0; i<vt[u].size(); i++)
27     {
28         int v=vt[u][i];
29         if(color[v]) ok=false; ///!!!性质1
30         if(!dfn[v])
31         {
32             tarjan(v);
33             if(low[v]>dfn[u]) ok=false; ///!!!性质2
34             if(low[v]<dfn[u]) cnt++;
35             if(cnt==2) ok=false;
36             low[u]=min(low[u],low[v]);
37         }
38         else if(instack[v])
39         {
40             low[u]=min(low[u],dfn[v]);  ///这里把时间戳dfn写成了low,错误了好几次
41             cnt++;
42             if(cnt==2) ok=false;   ///!!!性质3
43         }
44     }
45     if(low[u]==dfn[u]) ///有向图缩点
46     {
47         int v;
48         scnt++; ///强连通分量的个数
49         do
50         {
51             v=stack[top--];
52             instack[v]=0;
53             belong[v]=scnt;///!让一个强连通分量缩成一个点
54         }while(u!=v);
55     }
56     color[u]=1;
57 }
58 
59 int main()
60 {
61     int  T, u, v;
62     cin >> T;
63     while(T--)
64     {
65       for(int i=0; i<maxn; i++)
66         vt[i].clear();
67       cin >> n;
68       while(1)
69       {
70          scanf("%d%d",&u,&v);
71          if(u+v==0) break;
72          vt[u+1].push_back(v+1);
73       }
74       Init_tarjan();
75       ok=true;
76       for(int i=1; i<=n; i++)
77         if(!dfn[i]) tarjan(i);
78       printf((scnt==1&&ok==true)?"YES\n":"NO\n");
79     }
80 }
原文地址:https://www.cnblogs.com/kane0526/p/2817309.html