HDU 3844 Mining Your Own Business

    首先,若是圖原本就是一個點雙聯通的(即不存在割點),那麼從這個圖中選出任意兩個點就OK了。spa

    若是這個圖存在割點,那麼咱們把割點拿掉後圖就會變得支離破碎了。對於那種只和一個割點相連的塊,這個塊中至少要選一個點出來建逃生通道,並且能夠任意選擇,而對於那種和多個割點相連的塊則不必選點出來建逃生通道。code

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 100010
#define MAXM 100010
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long LL;
int dfn[MAXN], low[MAXN], h[MAXN], ind;
bool vis[MAXN];
int N, M, first[MAXN], e, next[MAXM], v[MAXM], col[MAXN];
struct Edge
{
    int x, y;
}edge[MAXM];
void dfs(int u, int p, int o)
{
    dfn[u] = low[u] = ++ ind;
    int cnt = 0;
    for(int i = first[u]; i != -1; i = next[i])
    {
        if(v[i] == p) continue;
        if(!dfn[v[i]])
        {
            ++ cnt;
            dfs(v[i], u, o);
            low[u] = std::min(low[u], low[v[i]]);
            if(u == o && cnt > 1) h[u] = 1;
            else if(u != o && low[v[i]] >= dfn[u]) h[u] = 1;
        }
        else low[u] = std::min(low[u], dfn[v[i]]);
    }
}
void tarjan()
{
    for(int i = 1; i <= N; i ++)
        low[i] = dfn[i] = h[i] = 0;
    ind = 0;
    dfs(i, -1, i);
}
void add(int x, int y)
{
    v[e] = y;
    next[e] = first[x], first[x] = e ++;
}
void input()
{
    N = 0;
    for(int i = 0; i < M; i ++)
    {
        scanf("%d%d", &edge[i].x, &edge[i].y);
        N = std::max(edge[i].x, N);
        N = std::max(edge[i].y, N);
    }
    memset(first, -1, sizeof(first[0]) * (N + 1)), e = 0;
    for(int i = 0; i < M; i ++)
        add(edge[i].x, edge[i].y), add(edge[i].y, edge[i].x);
}
void find(int x, int c, int &pn, int &cn)
{
    vis[x] = true, ++ pn;
    for(int i = first[x]; i != -1; i = next[i])
    {
        int y = v[i];
        if(vis[y]) continue;
        if(h[y])
        {
            if(col[y] != c) col[y] = c, ++ cn;
            continue;
        }
        find(y, c, pn, cn);
    }
}
void process()
{
    tarjan();
    memset(vis, 0, sizeof(vis[0]) * (N + 1));
    memset(col, 0, sizeof(col[0]) * (N + 1));
    LL ans = 1;
    int cnt = 0;
    for(int i = 1; i <= N; i ++)
        if(!h[i] && !vis[i])
        {
            int pn = 0, cn = 0;
            find(i, i, pn, cn);
            if(cn == 0) ans *= (LL)pn * (pn - 1) / 2, cnt += 2;
            else if(cn == 1) ans *= pn, ++ cnt;
        }
    printf("%d %I64d\n", cnt, ans);
}
int main()
{
    int t = 0;
    while(scanf("%d", &M), M > 0)
    {
        input();
        printf("Case %d: ", ++ t);
        process();
    }
    return 0;
}
相關文章
相關標籤/搜索