HDOJ 3594: Cactus

題目鏈接:

http://acm.hdu.edu.cn/showproblem.php?pid=3594


題目大意:

仙人掌圖的判定。

本題中的仙人掌圖是一種強連通圖,使得每條邊至多在一個環上。


算法:

仙人掌算是一種蠻流行的圖論模型吧。

wiki 上 Cactus Graph 的定義是:

一個無向連通圖,任兩個簡單環至多含有一個公共點,等價於任一條邊至多屬於一個簡單環,等價於任何一個塊都是一個點或一個環。

但是在實際的題目和文檔中,好像說是無向圖的也有,說是有向圖的也有。說是邊至多在一個環中的也有,說是點至多在一個環中的也有。╮(╯▽╰)╭

另外我還找到了一篇介紹仙人掌圖的中文文檔

文檔中介紹了仙人掌圖的三個性質:

性質 1: 仙人掌圖的 DFS樹沒有橫向邊。
性質 2: Low[v] <= DFS[u] (v 是 u 的兒子) 
性質 3: 設某個點 u 有 a(u) 個兒子的 low 值小於 DFS[u] ,同時 u 自己有 b(u) 條反向邊。那麼 a(u) + b(u) < 2。


當然這道題只是要我們判定,做法是非常簡單的。

直接很據仙人掌圖的三個性質判定。

性質一和二都很好判定。

性質三的話,在沒有橫叉邊的情況下,

設某個點 u 有 a(u) 個兒子的 low 值小於 DFS[u] ,同時 u 自己有 b(u) 條反向邊,

那麼a(u) + b(u)就等於使得low[v] < dep[u]的邊(u,v)的數量(因爲沒橫叉邊的話dep[v ] < dep[u]就是反向邊嘛,然後 low[v] <= dep[v])

這代碼。。全部都是 if 啊啊啊。。。


代碼:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <climits>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;

const int MAXN = 21000;
vector<int> mm[MAXN];
int low[MAXN], dep[MAXN];
bool ins[MAXN];
int cot[MAXN];
bool flg;

void dfs(int u, int p)
{
    int tmp = dep[u] = low[u] = (p == -1) ? 0 : dep[p] + 1;
    ins[u] = true;
    for(int i = 0; i < mm[u].size(); i ++)
    {
        int v = mm[u][i];
        if(dep[v] != -1 && !ins[v])
        {
            flg = false;  //cactus圖無橫叉邊
        }
        if(dep[v] == -1)
        {
            dfs(v, u);
        }
        if(low[v] > dep[u])
        {
            flg = false;  //cactus圖是強聯通的
        }
        if(low[v] < dep[u])
        {
            cot[u] ++;
            if(cot[u] > 1)
            {
                flg = false;  //設某個點u有a(u)個兒子的Low值小於DFS[u],同時 u 自己有 b(u)條逆向邊。那麼 a(u)+b(u)<2。
            }
        }
        tmp = min(low[v], tmp);
    }
    low[u] = tmp;
    ins[u] = false;
}

int main()
{
    int cas;
    scanf("%d", &cas);
    for(int T = 1; T <= cas; T ++)
    {
        int n;
        scanf("%d", &n);
        for(int i = 0; i < n; i ++)
        {
            mm[i].clear();
        }
        memset(dep, -1, sizeof(dep));
        memset(ins, 0, sizeof(ins));
        memset(cot, 0, sizeof(cot));
        flg = true;
        int u, v;
        while(scanf("%d %d", &u, &v), u || v)
        {
            mm[u].push_back(v);
        }
        dfs(0, -1);
        for(int i = 0; i < n; i ++)
        {
            if(dep[i] == -1)
            {
                flg = false;
            }
        }
        if(flg)
        {
            puts("YES");
        }
        else
        {
            puts("NO");
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章