IT民工
加油!

题意很容易弄懂,就是找到割点,以及割点连接的强连通分量的个数,简称连通数。用tarjan来

求,假设1为根结点,则连通数为0。其他点假设连通数为1。根据下面的定义来求。

if(low[pnt[i]] >= dfn[cur])
      sub[cur] ++;

【割点】

在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联

的边以后,原图变成多个连通块,就称这个点集为割点集合。当割点集合的顶点个数只有1个时,该

顶点就是割点。

此时,我们可以得到割点的定义如下:

若有k的儿子为i,我们定义AnceDeep[i]为结点i辈分最高(深度最浅)的祖先的深度,deep[k]为k的搜索深度(时间戳),那么k为割点当且仅当k满足(1)(2)中的一个:

(1)       若k为深搜树的根Root,当且仅当k的儿子数(分支数)>=2时k为割点;

(2)       若k为搜索树的中间结点(即k既不为根也不为叶),那么k必然有father和son,若AnceDeep[son]>= deep[k],则k必然为割点。

对于(1)是显然的,根结点k一旦有2个以上的分支,那么删除k必然出现森林;

对于(2)比较难理解,首先注意AnceDeep[son]>= deep[k]这个条件,意思就是“k的儿子son的辈分最高的祖先(暂且设其为w)的深度,比k的深度要深(或者等于k的深度,此时k就是w),就是说 k的辈分比w更高(深度更浅),那么一旦删除k,son所在的网络势必和 k的father所在的网络断开”,那么k就是割点。

/*Accepted    196K    0MS    C++    1807B    2012-07-30 15:50:57*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;

const int MAXN = 1 << 10;
const int MAXM = MAXN * MAXN;

int dfn[MAXN], low[MAXN], sub[MAXN];
int cnt, e, N;
int first[MAXN], next[MAXM], pnt[MAXM];
int x, y;
void tarjan(int cur)
{
    int i;
    dfn[cur] = low[cur] = ++ cnt;
    for(i = first[cur]; i != -1; i = next[i])
    {
        if(!dfn[pnt[i]])
        {
            tarjan(pnt[i]);
            if(low[pnt[i]] < low[cur])
                low[cur] = low[pnt[i]];
            if(low[pnt[i]] >= dfn[cur])
                sub[cur] ++;
        }
        else if(dfn[pnt[i]] < low[cur])
                low[cur] = dfn[pnt[i]];
    }
}

void solve()
{
    int i;
    memset(dfn, 0, sizeof dfn);
    for(i = 2; i <= N; i ++)
        sub[i] = 1;
    cnt = 0;
    sub[1] = 0;
    tarjan(1);
    int flag = 0;
    for(i = 1; i <= N; i ++)
    {
        if(sub[i] > 1){
            flag = 1;
            printf("  SPF node %d leaves %d subnets\n", i, sub[i]);
        }
    }
    if(!flag)
        printf( "  No SPF nodes\n");
}

void addedge(int x, int y)
{
    pnt[e] = y;
    next[e] = first[x], first[x] = e ++;
}

void ReadGraph()
{
    e = 0;
    memset(first, -1, sizeof first);
    scanf("%d", &y);
    addedge(x, y), addedge(y, x);
    N = max(N, max(x, y));
    for( ; ; )
    {
        scanf("%d", &x);
        if(x == 0) break;
        scanf("%d", &y);
        addedge(x, y), addedge(y, x);
        N = max(N, max(x, y));
    }
}

int main()
{
    int cas = 0;
    while(scanf("%d", &x) != EOF)
    {
        if(x == 0) break;
        ReadGraph();
        if(cas ++) printf("\n");
        printf("Network #%d\n", cas);
        solve();
    }
    return 0;
}
posted on 2012-07-30 15:59  找回失去的  阅读(267)  评论(0编辑  收藏  举报