您的位置:首页 > 其它

POJ 1523--SPF【无向图的所有割点 && 删去该点后bcc的数目】

2015-08-12 17:05 543 查看
SPF

Time Limit: 1000MSMemory Limit: 10000K
Total Submissions: 7066Accepted: 3218
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

Source

Greater New York 2000

第一道双连通分量的题, 求的是无向图的所有割点, 以及删去该点后bcc的数目。

看了图论算法理论的书一上午, 里面概念真心多 ,讲的挺好,但是代码风格不喜欢,后来阿宇让我看刘汝佳的训练指南,上面的概念和图论算法理论有点不用 ,但是更好理解。

先说一下tarjan算法里面几个重要的变量。

(1)dfs[ ] 记录各顶点的深度优先数

(2)low[ ]记录从该点或它的子孙出发 通过回边可以到达的最低深度优先数

更新low[u]有三点:均在tarjan中实现,取则三种中最小的low[ u ]

1,u本身的深度优先数dfn[u]

2,u的子节点中最低深度优先数(对没有查询过的,要每次更新)

3,u通过回边可以到达的最低优先数

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

(1) u 是具有两个以上子节点的深度深度优先生成树的根。

(2) u 存在一个 子节点 v 使得 low[ v ] >= dfn[ u ]。

去除割点 u 后,讲原来的连通图分成了几个连通分量

(1)如果割点 u 是根节点, 则有几个子节点,就分成几个连通分量

(2)如果割点 u 不是根节点,则有d个子节点 v, 使得low[ v ] >= dfn[ u ],则去掉 u 节点,分成d + 1个连通分量。

</pre></div><pre name="code" class="cpp">#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#define maxn 1000+10
#define maxm 2000000+10
using namespace std;

struct node {
    int u, v, next;
};

node edge[maxm];
int head[maxn], cnt;
int low[maxn];//从该点或它的子孙出发 通过回边可以到达的最低
int dfn[maxn];//该点的深度优先数
bool is_cut[maxn];//标记该点是不是割点
int add_bcc[maxn];//去掉该点增加的bcc数目
int dfs_clock;//深度优先数计数器
int bccno[maxn];//属于哪个bcc
int bcc_cnt;//bcc计数器

stack<node> S;//存储当前bcc中的边
vector<int>bcc[maxn];//存储bcc里面的点

void init(){
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void addedge(int u, int v){
    edge[cnt] = {u, v, head[u]};
    head[u] = cnt++;
    edge[cnt] = {v, u, head[v]};
    head[v] = cnt++;
}

int tarian(int u, int fa){
    low[u] = dfn[u] = ++dfs_clock;
    int son = 0;
    for(int i = head[u]; i != -1; i = edge[i].next){
        node E = edge[i];
        int v = E.v;
        if(!dfn[v]){
            S.push(E);
            son++;
            low[v] = tarian(v, u);
            low[u] = min(low[u], low[v]);
            if(u != fa && low[v] >= dfn[u]){ // u 是割点,但不是根节点
                is_cut[u] = true;
                //记录 u 有几个满足low[v] >= dfn[u]的子节点 v,
                //若有d个,去掉该割点后分成了 d + 1个连通分量。(这个 + 1会在后面输出的时候加上)
                add_bcc[u]++;
                //记录bcc里面的点
                bcc_cnt++;
                bcc[bcc_cnt].clear();
                while(1){
                    node A = S.top();
                    S.pop();
                    if(bccno[A.u] != bcc_cnt){
                        bcc[bcc_cnt].push_back(A.u);
                        bccno[A.u] = bcc_cnt;
                    }
                    if(bccno[A.v] != bcc_cnt){
                        bcc[bcc_cnt].push_back(A.v);
                        bccno[A.v] = bcc_cnt;
                    }
                    if(A.u == u && A.v == v) break;
                }
            }
        }
        else if(v != fa && dfn[v] < dfn[u]){
            S.push(E);
            low[u] = min(low[u], dfn[v]);//回边更新
        }
    }
    //u 是根节点, 但它的子节点只有一个,不是割点
    if(fa == u && son > 1) is_cut[u] = 1;
    //u 是根节点, 而且它的子节点个数 >= 2,是割点。删去该点后
    //u 有几个子节点, 就分成了几个bcc, 这里 先 son - 1, 后面输出的时候会 + 1.
    if(fa == u && son > 1) add_bcc[u] = son - 1;
    return low[u];
}

void find(int l, int r){
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(add_bcc, 0, sizeof(add_bcc));
    memset(is_cut, 0, sizeof(is_cut));
    memset(bccno, 0, sizeof(bccno));
    dfs_clock = bcc_cnt = 0;
    for(int i = l; i <= r; ++i)
        if(!dfn[i]) tarian(i, i);
}

int main (){
    int l, r;
    int a, b;
    int k = 1;
    while(1){
        init();
        l = 2000, r = 0;
        scanf("%d", &a);
        if(a == 0) return 0;
        l = min(a, l);
        r = max(a, r);
        scanf("%d", &b);
        l = min(b, l);
        r = max(b, r);
        addedge(a, b);
        while(scanf("%d", &a), a){
            l = min(a, l);
            r = max(a, r);
            scanf("%d", &b);
            l = min(b, l);
            r = max(b, r);
            addedge(a, b);
        }
        find(l, r);
        int flag = 0;
        printf("Network #%d\n", k++);
        for(int i = l; i <= r; ++i){
            if(is_cut[i]){
                flag = 1;
                printf("  SPF node %d leaves %d subnets\n", i, add_bcc[i] + 1);
            }
        }
        if(!flag)
            printf("  No SPF nodes\n");
        printf("\n");
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: