1. 程式人生 > >SPF (tarjan求割點及割點對應的連通分量數)

SPF (tarjan求割點及割點對應的連通分量數)

O - SPF

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

思路:

tarjan求割點(關鍵點)及割點對應的連通分量數

概念: 
在一個無向連通圖中,如果刪去某個頂點和與他相關聯的邊可以使得圖不連通,則稱該頂點為關節點。

關節點的求解tarjan演算法: 
在無向連通圖中,以某個頂點為根節點進行深度優先搜尋,則在深度優先搜尋樹中,每個節點都有一個深度優先數dfn[i]。如果u是v的祖先節點,那麼一定有dfn[u]< dfn[v]。 
回邊:在圖中有些邊不在深度優先搜尋生成樹中,則稱這些屬於圖但不屬於生成樹的邊為回邊。 
關節點的條件: 
1:如果在生成樹中,根節點有兩個或以上的孩子節點,那麼根節點為關節點。 
2:在生成樹中,一個頂點(不是根節點)若不是關節點,那麼他的所有的孩子節點一定可以通過回邊連線到該頂點的祖先節點。(由於形成了迴路,這樣刪去了該頂點後圖依然是連通的)否則該頂點為關節點。

我們為每個頂點u定義一個low值,low[u]表示從u或u的孩子出發通過回邊可以到達的最低深度優先數。 
所以上面的兩個條件轉化為了下面的一句話:u或者是具有兩個或以上子女的深度優先生成樹的根,或者雖然不是根,但他有一個子女w使得low[w]>= dfn[u]。(取等號的原因是即使能回到該頂點又沒用,因為會被刪掉。)

刪去關節點後把原來的圖分成了幾個連通分量? 
1:如果是根節點,則有幾個子女就分成幾個連通分量。 
2:不是根節點,則有d個子女w,使得low[w] >= dfn[u],就分成d+1個。
--------------------- 
作者:STILLxjy 
來源:CSDN 
原文:https://blog.csdn.net/stillxjy/article/details/52049394 
版權宣告:本文為博主原創文章,轉載請附上博文連結!

AC歷程:

要求出這些連線點的序號範圍,(最小值-最大值)minn-maxx(見程式碼)

輸出有兩個空格,一個換行

程式碼:

#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=2e3+7;
#define mem(a,b) memset(a,b,sizeof(a))
vector<int>ve[maxn];

//low[]i及i的子孫相連的輩分最高的祖先節點所在的深度
//tot樹深,T_cou連通分量的個數
//belong[]屬於哪個連通分量,in_stack[]是否在棧中
//subnets[u] 去掉結點u後,形成的連通分量
//in[]入度  out[]出度
int dfn[maxn],low[maxn];
int tot,n,ans;
int subnets[maxn];
int root;
void init()
{
    mem(dfn,0);
    mem(low,0);
    mem(subnets,0);
    tot=ans=0;
    for(int i=1; i<maxn; i++)
        ve[i].clear();
}
void tarjan(int x,int y)  //x為子節點,y為父節點
{
    dfn[x]=low[x]=++tot;
    int T_cou=0;
    for(int i=0; i<ve[x].size(); i++)  //i從0開始
    {
        int v=ve[x][i];

        if(!dfn[v])
        {
            tarjan(v,x);
            T_cou++;
            low[x]=min(low[x],low[v]); //若是v這個子節點能夠繞過父節點x到達更小的tot;
            //相當於x這個父節點也能到子節點的這個最小的tot;
            if(x==root&&T_cou>1)
                subnets[x]++;
            if(x!=root&&low[v]>=dfn[x])
                subnets[x]++;

        }
        else if(v!=y)
        {
            low[x]=min(low[x],dfn[v]);
        }
    }
}
int main()
{
    int u,v,maxx,minn,cas=1;
    while(~scanf("%d",&u)&&u)
    {
        init();
        maxx=-1;
        minn=0x3f3f3f3f;
        int flag=0;
        scanf("%d",&v);
        ve[u].push_back(v);
        ve[v].push_back(u);
        maxx=max(maxx,max(u,v));
        minn=min(minn,min(u,v));
        while(~scanf("%d",&u)&&u)
        {
            scanf("%d",&v);
            ve[u].push_back(v);
            ve[v].push_back(u);
            maxx=max(maxx,max(u,v));
            minn=min(minn,min(u,v));
        }
        root=minn;
        for(int i=1; i<=maxx; i++)
            tarjan(i,root);
        printf("Network #%d\n",cas++);
        for(int i=1; i<=maxx; i++)
        {
            if(subnets[i])
            {
                printf("  SPF node %d leaves %d subnets\n",i,subnets[i]+1);
                flag=1;
            }
        }
        if(flag==0)
            printf("  No SPF nodes\n");
        puts("");
    }
    return 0;
}