HIT ACM 1007题 单点故障SPF(图论,关节点与重连通分量)

在这里插入图片描述

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.Separate test cases with a blank line.

问题分析:

题意即为:找出所有特殊的顶点,即删掉该顶点以后,该连通图分为2个或者多个连通图。即找出所有关节点。上图中,左图的3节点将图分为两个连通图。

相关概念

关节点:假若在删去顶点 v v v以及和 v v v相关联的各边之后,将图的一个连通分量分割成两个或两个以上的连通分量,则称顶点 v v v为该图的一个关节点。

重连通图:一个没有关节点的连通图。(任意一对顶点之间至少存在两条路径,删去某个顶点以及依附于该顶点的各边时,不破坏图的连通性)

回边:在图中有些边不在深度优先搜索生成树中,则称这些属于图但不属于生成树的边为回边。

连通度:若在连通图上至少删去 k k k个顶点才能破坏图的连通性,则称此图的连通度为 k k k

解决方法

利用深度优先搜索,结合深度优先生成树,分析可知:

  • 若生成树的跟有两颗或两颗以上的子树,则此跟顶点必为关节点。因为途中不存在联结不同子树中顶点的边。因此,若删去根节点,生成树便生成森林。
  • 若生成树中某个非叶子顶点 v v v,其某颗子树的根和子树中的其他结点均没有指向 v v v的祖先的回边,则 v v v为关节点。因为若删去 v v v,则其子树和图的其他部分被分割开来。
  • 时间复杂度为 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n).
    如下图,为从左图的1节点深度遍历过程,实线箭头为遍历时的访问路径。虚线箭头为回溯的路径,指向虚线节点的实线为回边。3节点的子树中没有指向1 和 2 的回边。因此,3节点为关节点。

在这里插入图片描述

流程图

修改深度遍历的算法,为图重新定义遍历时的访问次序存储数组visited[ ],并为每个节点新增low,count信息,则通过一次遍历即可求得图中所有顶点的连通分量,即找出所有的关节点。
l o w ( v ) = M i n ( v i s i t e d [ v ] , l o w [ w ] , v i s i t e d [ k ] low(v) = Min(visited[v],low[w],visited[k] low(v)=Min(visited[v],low[w],visited[k]
其中 w w w v v v在深度优先搜索生成树的孩子节点; k k k v v v在深度遍历时由回边(虚线)连接的祖先节点。low表示节点及其子节点以及其回边能够连接的祖先的最小次序,若 l o w ( w ) &lt; v i s i t e d [ v ] low(w)&lt;visited[v] low(w)<visited[v] w w w v v v的一个子节点,则满足上述条件而,该父节点是关节点,该节点的count+1。

在这里插入图片描述
在深度遍历过程中,一个递归调用结束时表示该递归调用的子节点及其子节点的所有子节点的low值均被计算,因此,一次遍历即可找到所有关节点。

代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#define MAXLISTNUM 1024
#define MAX(a,b) ((a)<(b)?(b):(a))
#define MIN(a,b) ((a)>(b)?(b):(a))
typedef struct ArcNode{
    int adjvex;
    struct ArcNode *nextarc;
}ArcNode;
typedef struct VNode{
    int low;            /* judge nleaf point */
    int count;          /* biconnected num >1*/
    int subnode;
    ArcNode *firstarc;  /* to the first arcnode */
    ArcNode *endarc;
}VNode,AdjList[MAXLISTNUM]; /* 1024 node list  AdjList[i] is ith node,use from 1 */
typedef struct ALGraph{
    AdjList vertices;    /* array that contain 1024 VNode */
    int venum,arcnum;     /* vnode num and line num */
}*Graph;
void inputArc(Graph netlist,int x,int y); /* input arc data and node data */
void freeArc(Graph netlist);    /* free all arcNode */
void FindArticul(Graph netlist);
void DFS(Graph netlist,int nodeNum,int *accessCount,int *visited);
int main()
{
    Graph netlist=NULL;
    netlist = (Graph)malloc(sizeof(struct ALGraph));  /*initial the graph */
    netlist->arcnum = 0;
    netlist->venum = 0;
    memset(netlist->vertices,0,MAXLISTNUM*sizeof(struct VNode));
    int x,y,whileNum=1,i,flag=0;
    while(scanf("%d",&x)!=EOF){
        if(x == 0){
            break;
        }else{
            scanf("%d",&y);
            inputArc(netlist,x,y);
        }
        /* input a subnet */
        while(scanf("%d",&x)!=EOF){  /* ignore null line */
            if(x == 0){
                break;
            }else{
                scanf("%d",&y);
            }
            inputArc(netlist,x,y);
        }
        FindArticul(netlist);
        printf("Network #%d\n",whileNum);
        for(i=1;i<=netlist->venum;++i){
            if(netlist->vertices[i].count > 1){
                printf("  SPF node %d leaves %d subnets\n",i,netlist->vertices[i].count);
                flag = 1;
            }
        }
        if(flag == 0){
            printf("  No SPF nodes\n");
        }
        printf("\n");
        freeArc(netlist);
        ++whileNum;
        flag = 0;
        netlist->arcnum = 0;
        netlist->venum = 0;
        memset(netlist->vertices,0,MAXLISTNUM*sizeof(struct VNode));
    }
    free(netlist);
    return 0;
}
void inputArc(Graph netlist,int x,int y)
{
    netlist->venum = MAX(MAX(x,y),netlist->venum);  /* max num is the vnode num*/
    if(netlist->vertices[x].firstarc == NULL){      /* add <x,y> <y,x> */
        netlist->vertices[x].firstarc = (ArcNode*)malloc(sizeof(ArcNode));
        netlist->vertices[x].firstarc->adjvex = y;
        netlist->vertices[x].firstarc->nextarc = NULL;
        netlist->vertices[x].endarc = netlist->vertices[x].firstarc;
    }else{
        netlist->vertices[x].endarc->nextarc = (ArcNode*)malloc(sizeof(ArcNode));
        netlist->vertices[x].endarc->nextarc->adjvex = y;
        netlist->vertices[x].endarc->nextarc->nextarc = NULL;
        netlist->vertices[x].endarc = netlist->vertices[x].endarc->nextarc;
    }
    if(netlist->vertices[y].firstarc == NULL){
        netlist->vertices[y].firstarc = (ArcNode*)malloc(sizeof(ArcNode));
        netlist->vertices[y].firstarc->adjvex = x;
        netlist->vertices[y].firstarc->nextarc = NULL;
        netlist->vertices[y].endarc = netlist->vertices[y].firstarc;
    }else{
        netlist->vertices[y].endarc->nextarc = (ArcNode*)malloc(sizeof(ArcNode));
        netlist->vertices[y].endarc->nextarc->adjvex = x;
        netlist->vertices[y].endarc->nextarc->nextarc = NULL;
        netlist->vertices[y].endarc = netlist->vertices[y].endarc->nextarc;
    }
    ++netlist->arcnum;  //line num ++
}
void FindArticul(Graph netlist)
{
    int accessCount = 0;
    int visited[netlist->venum+1];  /* the access num */
    memset(visited,0,(netlist->venum+1)*sizeof(int));
    DFS(netlist,1,&accessCount,visited);   /* DFS from node 1 */
    if(netlist->vertices[1].subnode == 1){
        netlist->vertices[1].count = 1;  /* node 1 is not the special node */
    }else{
        netlist->vertices[1].count = netlist->vertices[1].subnode;  /* DFS */
    }
}
void DFS(Graph netlist,int nodeNum,int *accessCount,int *visited)
{
    ArcNode *pnode = NULL;
    netlist->vertices[nodeNum].count =1;
    netlist->vertices[nodeNum].low = INT_MAX;
    netlist->vertices[nodeNum].subnode = 0;
    (*accessCount)++;
    visited[nodeNum] = *accessCount; /* access the first node */
    for(pnode = netlist->vertices[nodeNum].firstarc;pnode;pnode = pnode->nextarc){
        if(visited[pnode->adjvex] == 0){  /* have not access the node,this is a sub node */
            DFS(netlist,pnode->adjvex,accessCount,visited);
            netlist->vertices[nodeNum].low = MIN(netlist->vertices[nodeNum].low,MIN(visited[nodeNum],netlist->vertices[pnode->adjvex].low));
            if(netlist->vertices[pnode->adjvex].low >= visited[nodeNum]){
                netlist->vertices[nodeNum].count++;
            }
            netlist->vertices[nodeNum].subnode++;
        }else{     /* not sub node */
            netlist->vertices[nodeNum].low = MIN(netlist->vertices[nodeNum].low,MIN(visited[nodeNum],visited[pnode->adjvex]));
        }
    }
}
void freeArc(Graph netlist)
{
    int i;
    ArcNode *ptemp;
    for(i=1;i<=netlist->venum;++i){
        while(netlist->vertices[i].firstarc != NULL){
            ptemp = netlist->vertices[i].firstarc->nextarc;
            free(netlist->vertices[i].firstarc);
            netlist->vertices[i].firstarc = ptemp;
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值