1. 程式人生 > >POJ 1523 SPF 割點與橋的判斷演算法-Tarjan

POJ 1523 SPF 割點與橋的判斷演算法-Tarjan

題目連結:

題意:

問一個連通的網路中有多少個關節點,這些關節點分別能把網路分成幾部分

題解:

Tarjan 演算法模板題

順序遍歷整個圖,可以得到一棵生成樹:

樹邊:可理解為在DFS過程中訪問未訪問節點時所經過的邊,也稱為父子邊

回邊:可理解為在DFS過程中遇到已訪問節點時所經過的邊,也稱為返祖邊、後向邊

對根節點u,若其有兩棵或兩棵以上的子樹,則該根結點u為割點;

對非葉子節點u(非根節點),若其子樹的節點均沒有指向u的祖先節點的回邊,說明刪除u之後,根結點與u的子樹的節點不再連通;則節點u為割點。


// 當(u,v)為樹邊且low[v]>dfn[u]時,表示v節點只能通過該邊(u,v)與u連通,那麼(u,v)即為割邊。

用一個數組儲存每個節點的子樹個數即可

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define maxn 1050
using namespace std;
int dfn[maxn],low[maxn];          //dfs序  和子樹連線的最小節點
int vis[maxn];
vector<int>edge[maxn];   
int child[maxn];
int num,son;
void init()
{
    memset(vis,0,sizeof(vis));
    memset(child,0,sizeof(child));
    vis[1]=1;
    num=0;
    son=0;
}
void Tarjan(int u)
{
    dfn[u]=low[u]=++num;
    vis[u]=1;
    for(int i=0; i<edge[u].size(); i++)
    {
        int v=edge[u][i];
        if(!vis[v])
        {
            Tarjan(v);
            low[u]=min(low[u],low[v]);
            if(dfn[u]<=low[v])       //得到子樹
            {
                if(u!=1)
                    child[u]++;
                else
                    son++;
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
}
int main()
{
//    freopen("in.txt","r",stdin);
    int a,b;
    int Case=1;
    while(1)
    {
        while(scanf("%d",&a)&&a)
        {

            scanf("%d",&b);
            edge[a].push_back(b);
            edge[b].push_back(a);
        }
        init();

        Tarjan(1);
//        for(int i=1;i<=5;i++)
//        cout<<dfn[i]<<" "<<low[i]<<endl;
        if(Case>1)
            cout<<endl;
        printf("Network #%d\n",Case++);
        int flag=1;
        child[1]=son-1;
        for(int i=1; i<=1000; i++)
            if(child[i]>0)
            {
                flag=0;
                printf("  SPF node %d leaves %d subnets\n",i,child[i]+1);
            }
        if(flag)
            cout<<"  No SPF nodes"<<endl;


        for(int i=1; i<=1000; i++)
            edge[i].clear();
        scanf("%d",&a);
        if(a==0)
            break;
        scanf("%d",&b);
        edge[a].push_back(b);
        edge[b].push_back(a);
    }
    return 0;
}