首先,如果图本来就是一个点双联通的(即不存在割点),那么从这个图中选出任意两个点就OK了。

    如果这个图存在割点,那么我们把割点拿掉后图就会变得支离破碎了。对于那种只和一个割点相连的块,这个块中至少要选一个点出来建逃生通道,而且可以任意选择,而对于那种和多个割点相连的块则没必要选点出来建逃生通道。

#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;
}

 

posted on 2013-10-11 19:40  Staginner  阅读(740)  评论(0编辑  收藏  举报