HDU --- 3594 Cactus 【仙人掌图的运用】

传送门
//题意就是判给的这幅图是不是一幅仙人掌图.
仙人掌图分析
//仙人掌图应该满足如下规则
1:仙人掌图的dfs树没有横向边
2:dfn[u] >= low[v] (v是u的儿子)
3 : 设某个点v 有a(v)个儿子的low值小于dfn(v), 同时v自己有b(v)条逆向边. 那么a(v) + b(v) < 2.
只要不满足上面任意一个条件,则该图就不是仙人掌图.
所以跟着这个敲呗.
AC Code

/** @Cain*/
const int maxn=1e5+5;
int cas=1;
int n,m;
int res,cnt;
vector<int>G[maxn];
stack<int>S;
int dfn[maxn],low[maxn],bel[maxn];
bool vis[maxn];
bool flag;
void init()
{
    Fill(dfn,0);
    Fill(low,0);Fill(bel,0);
    Fill(vis,false);
    for(int i=1;i<=n;i++) G[i].clear();
    res = 0;
    cnt = 1;
    flag = true;
}
void tarjan(int u)
{
    dfn[u] = low[u] = cnt++;
    S.push(u);
    int sum = 0;
    for(int i=0; iint nex = G[u][i];
        if(vis[nex]) flag = false;  //性质一. 如果下一个访问的点访问过,这就是一条横向边.
        if(!dfn[nex]){
            tarjan(nex);
            low[u] = min(low[u],low[nex]);
            if(low[nex] > dfn[u]) flag = false;  //性质二
            if(low[nex] < dfn[u]) sum++;       //性质三.
            if(sum >= 2) flag = false;
        }
        else if(!bel[nex]){
            low[u] = min(low[u],dfn[nex]);
            sum++;
            if(sum >= 2) flag = false;   //性质三.
        }
    }
    if(low[u] == dfn[u]){
        res++;
        while(1){
            int v = S.top();
            S.pop();
            bel[v] = res;
            if(v == u) break;
        }
    }
    vis[u] = true;
}
void solve()
{
    scanf("%d",&n);
    init();
    while(1){
        int u,v;
        scanf("%d%d",&u,&v);
        if(u + v == 0) break;
        u++; v++;
        G[u].push_back(v);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    if(flag) puts("YES");
    else puts("NO");
}
int main()
{
    int t = 1 ;
    scanf("%d",&t);
    while(t--){
    //    printf("Case %d: ", cas++);
        solve();
        //printf("\n");
    }
}

你可能感兴趣的:(仙人掌图)