求连通图的割点(关节点)问题

割点的定义是,如果除去此节点和与其相关的边,图不再连通。

分析:

1. 最简单也是最直接的算法是,删除一个点然后判断连通性,如果删除此点,图不再连通,则此点是割点,反之不是割点(图的连通性一般通过深搜来判定,是否能一次搜索完 全部顶点);该方法复杂度较高为O(n^3)。当然具体实现并不真正去掉每个顶点(及其关联边),只需跳过该点就可以了。

2. 通过深搜优先生成树来判定。从任一点出发深度优先遍历得到优先生成树,对于树中任一顶点u而言,其孩子节点为邻接点。

顶点u是割点的充要条件:

1)如果顶点u是深度优先搜索生成树的根,则u至少有2个子女。

2)如果u不是生成树的根,则它至少有一个子女w,从w出发,不可能通过w、w的子孙,以及一条回边组成的路径到达u的祖先。

因此,对每个顶点u定义一个low值:low[u]是从u或u的子孙出发通过回边可以到达的最低深度优先数。low[u]定义如下:

low[u]=min{dnf[u],min{low[w]|w是u的一个子女},min{dnf[v]|v与u邻接,且(u,v)是一条回边}}

即low[u]取三者的最小值,其中第一项为他本身的深度优先数;第二项为他的子女顶点w的low[w]的最小值,因为它的子女可以到达的最低深度优先数,则它也可以通过子女到达。

第三项为它直接通过回边到达的最低深度优先数。

顶点u是割点的充要条件:顶点u是深度优先搜索生成树的根,则u至少有2个子女或不是根,但他有一个子女w,使得low[w]>=dnf[u].


看题:POJ 1532  SPF

Description
Consider the two networks shown below. Assuming that data moves around these networks only between directly connected nodes on a peer-to-peer basis, a failure of a single node, 3, in the network on the left would prevent some of the still available nodes from communicating with each other. Nodes 1 and 2 could still communicate with each other as could nodes 4 and 5, but communication between any other pairs of nodes would no longer be possible.

Node 3 is therefore a Single Point of Failure (SPF) for this network. Strictly, an SPF will be defined as any node that, if unavailable, would prevent at least one pair of available nodes from being able to communicate on what was previously a fully connected network. Note that the network on the right has no such node; there is no SPF in the network. At least two machines must fail before there are any pairs of available nodes which cannot communicate. 

                              

Input
The input will contain the description of several networks. A network description will consist of pairs of integers, one pair per line, that identify connected nodes. Ordering of the pairs is irrelevant; 1 2 and 2 1 specify the same connection. All node numbers will range from 1 to 1000. A line containing a single zero ends the list of connected nodes. An empty network description flags the end of the input. Blank lines in the input file should be ignored.
Output
For each network in the input, you will output its number in the file, followed by a list of any SPF nodes that exist.

The first network in the file should be identified as "Network #1", the second as "Network #2", etc. For each SPF node, output a line, formatted as shown in the examples below, that identifies the node and the number of fully connected subnets that remain when that node fails. If the network has no SPF nodes, simply output the text "No SPF nodes" instead of a list of SPF nodes.
Sample Input
1 2
5 4
3 1
3 2
3 4
3 5
0

1 2
2 3
3 4
4 5
5 1
0

1 2
2 3
3 4
4 6
6 3
2 5
5 1
0

0
Sample Output
Network #1
SPF node 3 leaves 2 subnets

Network #2
No SPF nodes

Network #3
SPF node 2 leaves 2 subnets
SPF node 3 leaves 2 subnets

题意就是求无向连通图的割点,并求去掉该割点后分为几个联通图。

#include<cstdio>
#include<cstring>
#define min(a,b) ((a)<(b)?(a):(b))
int Edge[1001][1001];///邻接矩阵
int visited[1001];///顶点访问状态
int nodes;///顶点数目
int tmpdnf;///在dfs中记录当前深度优先搜索序数
int dnf[1001];
int low[1001];///根据该值来判断是否为关节点
int son;///根节点子女个数(如果根节点子女个数大于等于2,根节点是关节点)
int subnets[1001];///记录每个节点去掉该节点后连通分量的个数
void dfs(int u)
{
    for(int v=1;v<=nodes;v++)
    {///v跟u邻接在生成树中就是2种情况
        ///(1)v是u的祖先,这样(v,u)就是一条回边.(2)v是u的儿子节点
        if(Edge[u][v])
        {
            if(!visited[v])///v还未访问,v是u的儿子节点
            {
                visited[v]=1;
                tmpdnf++;
                dnf[v]=low[v]=tmpdnf;
                dfs(v);///执行完后,low[v]值以求出
                low[u]=min(low[u],low[v]);///回退时计算u的low值
                if(low[v]>=dnf[u])
                {
                    if(u!=1)
                        subnets[u]++;///去掉该节点后连通分量的个数
                    if(u==1)///根节点子女个数(如果根节点子女个数大于等于2,根节点是关节点)
                        son++;
                }
            }
            else///v是u的祖先,这样(v,u)就是一条回边
                low[u]=min(low[u],dnf[v]);
        }
    }
}
void init()///初始化函数
{
    low[1]=dnf[1]=1;
    tmpdnf=1;
    son=0;
    memset(visited,0,sizeof(visited));
    visited[1]=1;
    memset(subnets,0,sizeof(subnets));
}
int main()
{
    int i;
    int u,v;///输入的顶点对
    int find;///是否找到割点的标志
    int number=1;
    while(1)
    {
        scanf("%d",&u);
        if(u==0)
            break;///整个输入结束
            memset(Edge,0,sizeof(Edge));
            nodes=0;
        scanf("%d",&v);
        if(u>nodes)
            nodes=u;
        if(v>nodes)
            nodes=v;
        Edge[u][v]=Edge[v][u]=1;
        while(1)
        {
            scanf("%d",&u);
            if(u==0)
                break;///当前输入结束
            scanf("%d",&v);
            if(nodes<u)
                nodes=u;
                if(nodes<v)
                    nodes=v;
                Edge[u][v]=Edge[v][u]=1;
        }
            printf("Network #%d\n",number++);
            init();
            dfs(1);
            if(son>1)
                subnets[1]=son-1;
            find=0;
            for(i=1;i<=nodes;i++)
            {
                if(subnets[i])
                {
                    find=1;
                    printf("  SPF node %d leaves %d subnets\n",i,subnets[i]+1);
                }
            }
            if(!find)
                printf("  No SPF nodes\n");
                printf("\n");
    }
}


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值