POJ1523 SPF【点双连通分量】【Tarjan】

来源:互联网 发布:淘宝开店邮费是多少 编辑:程序博客网 时间:2024/05/16 15:24

题目链接:

http://poj.org/problem?id=1523


题目大意:

有一个网络,在这个网络里,电脑之间的通信只能是两台电脑间(点对点)双向通信。如下面左图

所示:如果3号电脑出故障了,那么1号和2号之间、4号和5号之间还可以通信,不过1、2和3、4

号电脑之间就不能通信了,那么3号电脑就是一个SPF节点,且3号电脑故障后,整个网络被分为

了2个子网络。那么问题来了:给你一些边。问删除某个SPF节点后,可以将图分为几个连通分量。



思路:

其实就是给你一个连通图,求出这个连通图的所有割点编号,并求出若删去其中一个割点后,原网

络被分成几个子网络。这里我们使用的思路和Tarjan算法类似。

(1)对原图进行深度优先搜索,计算树上每一个节点v的搜索深度标号dfn[v]。

(2)计算所有节点v的low[v]是在深度优先搜索树上按照后根遍历的顺序进行的。所以,当访问节点v

时它的儿子u的low[u]已经计算完毕,这时low[v]取下面三个值中的最小值。1.dfn[v]、2.dfn[w](凡

是含有回退边(v,w)的任何节点w)、3.low[u](对v的任何儿子u)

(3)然后判断一个点是不是割点,如果一个节点v是割点,满足下面两种情况。

1.v为树根,且v有多于一个子树;2.v不为树根,且满足存在边(v,u),使得dfn[v] <= low[u]。

注:我在程序中定义son[v]为节点v的深度,深度优先搜索时,每入栈一次,son[v]+1,每退栈一次,

son[v]-1。


AC代码:

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;const int MAXN = 1010;const int MAXM = MAXN*MAXN;struct EdgeNode{    int to;    int next;}Edges[MAXM];int Head[MAXN];int dfn[MAXN],low[MAXN],Stack[MAXN],son[MAXN];int m,id,scc,lay,N;void AddEdges(int u,int v){    Edges[id].to = v;    Edges[id].next = Head[u];    Head[u] = id++;}void TarjanBFS(int pos,int from){    Stack[m++] = pos;    dfn[pos] = low[pos] = ++lay;    for(int i = Head[pos]; i != -1; i = Edges[i].next)    {        if(Edges[i].to == from)            continue;        if( !dfn[Edges[i].to])        {            TarjanBFS(Edges[i].to,pos);            low[pos] = min(low[pos],low[Edges[i].to]);            if( dfn[pos] <= low[Edges[i].to] )            {                while(Stack[m--] != Edges[i].to);                son[pos]++;            }        }        else            low[pos] = min(low[pos],low[Edges[i].to]);    }}int main(){    int u,v,kase = 0;    while(~scanf("%d",&u) && u)    {        N = -1;        m = lay = scc = id = 0;        memset(dfn,0,sizeof(dfn));        memset(low,0,sizeof(low));        memset(son,0,sizeof(son));        memset(Head,-1,sizeof(Head));        N = max(N,u);        scanf("%d",&v);        N = max(N,v);        AddEdges(u,v);        AddEdges(v,u);        while(scanf("%d",&u) && u)        {            N = max(N,u);            scanf("%d",&v);            N = max(N,v);            AddEdges(u,v);            AddEdges(v,u);        }        printf("Network #%d\n",++kase);        TarjanBFS(1,0);        son[1]--;        int flag = 0;        for(int i = 1; i <= N; ++i)        {            if(son[i] > 0)            {                printf("  SPF node %d leaves %d subnets\n", i, son[i]+1);                flag = 1;            }        }        if(flag == 0)            printf("  No SPF nodes\n");        printf("\n");    }    return 0;}


0 0