1. 程式人生 > >poj1144 求割點的個數(注意輸入的格式)

poj1144 求割點的個數(注意輸入的格式)

描述

電話線公司(TLC)正在建立一個新的電話電纜網路。它們連線了幾個從1到N的整數編號的位置。沒有兩個地方有相同的號碼。線路是雙向的,並且總是將兩個地方連線在一起,並且在每個地方線路終止於電話交換機。每個地方都有一個電話交換機。它來自每個地方 
可以通過其他地方的線路到達,但它不需要是直接連線,它可以通過幾個交換。電源有時會在一個地方發生故障,然後交換機無法執行。TLC的官員意識到,在這種情況下,除了失敗的地方無法到達之外,還可能導致其他地方無法相互連線。在這種情況下,我們會說這個地方(
發生故障的地方 )是至關重要的。現在,官員正試圖編寫一個程式來查詢所有這些關鍵位置的數量。幫助他們。

輸入

輸入檔案由幾個行塊組成。每個塊描述一個網路。在每個塊的第一行中,存在N <100的位數。接下來最多N行中的每一行包含一個地點的數字,後面跟有來自該地方的直線的一些地方的數量。這些最多N行完全描述了網路,即,網路中兩個位置的每個直接連線至少包含在一行中。一行中的所有數字
由一個空格分隔 。每個塊以一條僅包含0的行結束。最後一個塊只有一行,N = 0;

產量

輸出包含除輸入檔案中的最後一個塊之外的每個塊,其中一行包含關鍵位置的數量。

樣本輸入

<span style="color:#000000">
5
5 1 2 3 4
0
6
2 1 3
5 4 6 2
0
0
</span>

樣本輸出

<span style="color:#000000">
1
2
</span>

 題意:

給你一個無向圖,問你這個圖中有多少個割點.不過該題的輸入格式說的比較難懂.這裡解釋一下:每個例項第一行是N,表示節點數.接下來可能有最多N行描述邊資訊的.

        其中這N行每行都是這樣的:每行第一個數表示該行的主頂點u,接著的所有數字表示副頂點v1,v2,v3…等.表示u與v1,u與v2,u與v3分別都有一條邊.

        最後這個例項以一個0表示結束.

        當然所有例項之後還有一個0(N=0),表示輸入結束.
程式碼如下:

//求無向圖的割頂和橋

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
const int maxn=1000+10;
int n,m;
int dfs_clock;//時鐘,每訪問一個節點增1
vector<int> G[maxn];//G[i]表示i節點鄰接的所有節點
int pre[maxn];//pre[i]表示i節點被第一次訪問到的時間戳,若pre[i]==0表示i還未被訪問
int low[maxn];//low[i]表示i節點及其後代能通過反向邊連回的最早的祖先的pre值
bool iscut[maxn];//標記i節點是不是一個割點

//求出以u為根節點(u在DFS樹中的父節點是fa)的樹的所有割頂和橋
//初始呼叫為dfs(root,-1);
int dfs(int u,int fa)  //直接用模板就行了
{
    int lowu=pre[u]=++dfs_clock;
    int child=0;    //子節點數目
    for(int i=0; i<G[u].size(); i++)
    {
        int v=G[u][i];
        if(!pre[v])
        {
            child++;//未訪問過的節點才能算是u的孩子
            int lowv=dfs(v,u);
            lowu=min(lowu,lowv);
            if(lowv>=pre[u])
            {
                iscut[u]=true;      //u點是割頂
              /*  if(lowv>pre[u])   //(u,v)邊是橋
                    printf("邊(%d, %d)是橋\n",u,v);*/
            }
        }
        else if(pre[v]<pre[u] && v!=fa)//v!=fa確保了(u,v)是從u到v的反向邊
        {
            lowu=min(lowu,pre[v]);
        }
    }
    if(fa<0 && child==1 )
        iscut[u]=false;//u若是根且孩子數<=1,那u就不是割頂
    return low[u]=lowu;
}

int main()
{
    while(scanf("%d",&n)==1&&n)
    {
        dfs_clock=0;
        memset(pre,0,sizeof(pre));
        memset(iscut,0,sizeof(iscut));
        for(int i=1;i<=n;i++) G[i].clear();
        
        int a,b;
         while(scanf("%d",&a)&&a)
        {
            while(getchar()!='\n')
            {
                scanf("%d",&b);

               G[a].push_back(b);
                    G[b].push_back(a);
            }
        }


        dfs(1,-1);
        int ans=0;
        for(int i=1;i<=n;i++)if(iscut[i]==true)
          ans++;

          cout<<ans<<endl;
    }
    return 0;
}