<题目链接>
<转载于 >>> >
题目大意:
给你一个图,让你判断他是不是仙人掌图。
仙人掌图的条件是:
1、是强连通图。
2、每条边在仙人掌图中只属于一个强连通分量。仙人掌图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 <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 #define rep(i,s,t) for(int i=s;i<=t;i++) 7 #define clr(a,b) memset(a,b,sizeof(a)) 8 const int N = 2e4+10; 9 const int M = 5e4+10; 10 int head[N],dfn[N],low[N],belong[N],stk[N]; 11 bool color[N],instk[N],ok; 12 int n,top,tot,index,scnt; 13 struct Edge{ 14 int to,next; 15 }edge[M]; 16 void init(){ 17 tot=top=index=scnt=0; 18 clr(head,-1);clr(dfn,0);clr(low,0);clr(belong,0); 19 clr(stk,0);clr(instk,false);clr(color,false); 20 } 21 void addedge(int u,int v){ 22 edge[tot].to=v,edge[tot].next=head[u]; 23 head[u]=tot++; 24 } 25 void Tarjan(int u){ 26 dfn[u]=low[u]=++index; 27 stk[++top]=u,instk[u]=true; 28 int cnt=0; 29 for(int i=head[u];~i;i=edge[i].next){ 30 int v = edge[i].to; 31 if(color[v])ok=false; //性质1 32 if(!dfn[v]){ 33 Tarjan(v); 34 if(low[v]>dfn[u])ok=false; //性质2 35 if(low[v]<dfn[u])cnt++; //u的子节点中low值小于dfn[u]值得个数 36 if(cnt==2)ok=false; 37 low[u]=min(low[u],low[v]); 38 }else if(instk[v]){ 39 low[u]=min(low[u],dfn[v]);cnt++; 40 if(cnt==2)ok=false; //性质3 41 } 42 } 43 if(dfn[u]==low[u]){ 44 scnt++; 45 while(true){ 46 int v=stk[top--]; 47 instk[v]=false; 48 belong[v]=scnt; 49 if(v==u)break; 50 } 51 } 52 color[u]=true; 53 } 54 int main(){ 55 int T;scanf("%d",&T);while(T--){ 56 scanf("%d",&n); 57 init(); 58 int u,v;while(scanf("%d%d",&u,&v),u||v){ 59 u++,v++; 60 addedge(u,v); 61 } 62 ok=true; 63 rep(i,1,n) if(!dfn[i]) { 64 Tarjan(i); 65 } 66 printf((scnt==1&&ok==true)?"YES ":"NO "); 67 } 68 }
2018-12-06