【来源】
2010 ACM-ICPC Multi-University Training Contest(16)——Host by NUDT
Nada Open 2002
HDU-3594
UVA-10510
Kattis-cactus
vjudge
以上题库题目大意相同,但题目描述、输入格式不同,代码以HDU为准。
【题目描述】
1.It is a Strongly Connected graph.
2.Each edge of the graph belongs to a circle and only belongs to one circle.
We call this graph as CACTUS.
1.这是一个强连通图。
2.图形的每个边都属于一个圆,并且仅属于一个圆。
我们称此图为仙人掌图。
There is an example as the figure above. The left one is a cactus, but the right one isn’t. Because the edge (0, 1) in the right graph belongs to two circles as (0, 1, 3) and (0, 1, 2, 3).
上图有一个例子。左边的是仙人掌图,而右边的不是。因为右图中的边(0,1)属于两个圆,分别为(0,1,3)和(0,1,2,3)。
【输入格式】
The input consists of several test cases. The first line contains an integer T (1<=T<=10), representing the number of test cases.
For each case, the first line contains a integer n (1<=n<=20000), representing the number of points.
The following lines, each line has two numbers a and b, representing a single-way edge (a->b). Each case ends with (0 0).
Notice: The total number of edges does not exceed 50000.
输入包含几个测试用例。第一行包含一个整数T(1 <= T <= 10),代表测试用例的数量。
对于每种情况,第一行都包含一个整数n(1 <= n <= 20000),代表点数。
在以下几行中,每行都有两个数字a和b,分别表示单向边缘(a-> b)。每种情况都以(0 0)结尾。
注意:边的总数不超过50000。
【输出格式】
For each case, output a line contains “YES” or “NO”, representing whether this graph is a cactus or not.
对于每种情况,输出的行均包含“是”或“否”,代表该图是否为仙人掌。
【样例输入】
2
4
0 1
1 2
2 0
2 3
3 2
0 0
4
0 1
1 2
2 3
3 0
1 3
0 0
【样例输出】
YES
NO
【解析】
解题思路:
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的逆向边条数。
三个性质有一个不满足则不是仙人掌图。
【代码】
#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=5e5;
const int inf=1e9;
struct Node {
int to,nt;
} e[N];
int n,m,cnt,tot,num,top,index,flag;
int h[N],fa[N],dfn[N],low[N],instack[N],stap[N],belong[N],vis[N];
inline void add(int x,int y) {
e[cnt].to=y;
e[cnt].nt=h[x];
h[x]=cnt++;
}
void tarjan(int u) {
int v;
dfn[u]=low[u]=++index;
instack[u]=1;
stap[++top]=u;
for(int i=h[u]; i!=-1; i=e[i].nt) {
v=e[i].to;
if(!dfn[v]) {
fa[v]=u;
tarjan(v);
if(low[u]>low[v]) low[u]=low[v];
} else if(instack[v]) {
if(dfn[v]<low[u]) low[u]=dfn[v];
int tmp=u;
while(v!=fa[tmp]) {
vis[tmp]++;
if(vis[tmp]>1) {
flag=1;
return;
}
tmp=fa[tmp];
}
}
}
if(low[u]==dfn[u]) {
tot++;
do {
v=stap[--top];
instack[v]=0;
belong[v]=tot;
} while(v!=u);
}
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
tot=top=index=flag=0;
memset(h,-1,sizeof(h));
memset(fa,0,sizeof(fa));
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(vis,0,sizeof(vis));
int n;
scanf("%d",&n);
while(1) {
int x,y;
scanf("%d%d",&x,&y);
if(x==0 && y==0) break;
add(x+1,y+1);
}
for(int i=1; i<=n; i++) {
if(!dfn[i]) tarjan(i);
}
if(tot>1 || flag) {
puts("NO");
} else puts("YES");
}
return 0;
}