題目鏈接: http://acm.hdu.edu.cn/showproblem.php?pid=3594
性質:
先給出一個仙人掌的詳解: https://files-cdn.cnblogs.com/files/ambition/cactus_solution.pdf
我稍微說一下自己目前大概的理解吧,仙人掌樹剛剛入門做完板題的說,網上也沒什麼人解釋,只能自己先大概講講,如果有問題的歡迎指正。
仙人掌圖按照圖的邊的方向性分兩種,有向仙人掌圖和無向圖仙人掌圖。
有向圖仙人掌圖
有向圖仙人掌圖,按照目前能看得到的資料,首先要滿足的是一個整個的強連通圖,每一條邊必須在且僅在一個強連通塊內。
所以就有了它的三條性質;
① 仙人掌圖的 樹不存在橫向邊。(橫向邊的定義可以看上面鏈接中的圖,大概意思就是dfs的過程中不存在訪問到的新點是曾經被訪問過的點)
② ( )
③ 設某個點 有可到達的點集爲 那麼滿足條件 且 的點 的個數小於 ( 也可能爲 的父鏈結點)
無向仙人掌圖
已有知識來看,無向仙人掌圖中要求所有的邊,是橋或者只在一個簡單環中。
bzoj上好像有一些相應的題目。。但是現在oj炸了。。我得先去學了。。
hdu3594代碼
代碼
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep_e(i,u) for(int i=head[u];~i;i=nex[i])
using namespace std;
const int maxn=20005;
const int maxm=50005;
typedef long long ll;
int dfn[maxn],low[maxn],sta[maxn],top,flag,n,belong[maxn];
int head[maxn],to[maxm],nex[maxm],cnt,vis[maxn],qiang;
void add(int u,int v){
to[cnt]=v;nex[cnt]=head[u];
head[u]=cnt++;
}
void tarjan(int x){
if(flag) return ;
dfn[x]=low[x]=++cnt;
sta[++top]=x;
rep_e(i,x){
int v=to[i];
if(vis[v]) flag=1;
if(!dfn[v]){
tarjan(v);
low[x]=min(low[x],low[v]);
}
else if(!belong[v]) low[x]=min(low[x],low[v]);
}
if(dfn[x]==low[x]){
qiang++;
if(qiang>1) {flag=1; return ;}
while(1){
int u=sta[top--];
belong[u]=qiang;
if(u==x) break;
}
}
vis[x]=1;
}
void init(){
cnt=0; flag=0; top=0;qiang=0;
rep(i,1,n) {
head[i]=-1,vis[i]=0;
dfn[i]=low[i]=0;
belong[i]=0;
}
}
int main(){
int T; scanf("%d",&T);
while(T--){
scanf("%d",&n);
init();
int x,y;
while(~scanf("%d%d",&x,&y)){
if(x==0&&y==0) break;
x++,y++;
add(x,y);
}
rep(i,1,n){
if(!dfn[i]) tarjan(i);
}
if(flag) {
printf("NO\n"); continue;
}
rep(u,1,n){
int nu=0;
rep_e(i,u){
int v=to[i];
if(low[v]>dfn[u]) flag=1;
if(low[v]<dfn[u]) nu++;
}
if(nu>=2) flag=1;
}
if(flag) printf("NO\n");
else printf("YES\n");
}
return 0;
}