仙人掌图

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

性质:

先给出一个仙人掌的详解: https://files-cdn.cnblogs.com/files/ambition/cactus_solution.pdf

我稍微说一下自己目前大概的理解吧,仙人掌树刚刚入门做完板题的说,网上也没什么人解释,只能自己先大概讲讲,如果有问题的欢迎指正。

仙人掌图按照图的边的方向性分两种,有向仙人掌图和无向图仙人掌图。

有向图仙人掌图

有向图仙人掌图,按照目前能看得到的资料,首先要满足的是一个整个的强连通图,每一条边必须在且仅在一个强连通块内。

所以就有了它的三条性质;

① 仙人掌图的 d f s dfs dfs 树不存在横向边。(横向边的定义可以看上面链接中的图,大概意思就是dfs的过程中不存在访问到的新点是曾经被访问过的点)
l o w [ v ] < = d f n [ u ] low[v] <= dfn[u] low[v]<=dfn[u] ( f a [ v ] = u fa[v]=u fa[v]=u )
③ 设某个点 u u u 有可到达的点集为 S ( u ) S(u) S(u) 那么满足条件 v ∈ S ( u ) v\in S(u) vS(u) l o w [ v ] < d f n [ u ] low[v]<dfn[u] low[v]<dfn[u] 的点 v v v 的个数小于 2 2 2 v v v 也可能为 u u u 的父链结点)

无向仙人掌图

已有知识来看,无向仙人掌图中要求所有的边,是桥或者只在一个简单环中。

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值