POJ 1523 SPF

题意很容易弄懂,就是找到割点,以及割点连接的强连通分量的个数,简称连通数。用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;

}

你可能感兴趣的:(poj)