1. 程式人生 > >演算法學習之 圖的割點

演算法學習之 圖的割點

一.圖的割點

先解釋一下什麼叫圖的割點吧,割點就是如果去掉這個點之後無法實現所有點的相互連通,那麼這個點就是割點。

二.尋找圖的割點

那麼給定一張圖怎麼找到圖的割點呢,當然了,所謂割點當然應該是一個圖裡只有一個強聯通分量吧,那麼說一下我們大致的演算法,我們判斷一個節點u是否是割點,就是判讀他的子節點中是否存在節點不經過這個節點就無法回到祖先,如果是這樣的,那麼這個節點就是割點。我們用dfn[u]來記錄訪問到u的時間戳,low[u]來記錄u節點在不經過其父節點所能訪問到的最早時間戳(就是第一個能夠訪問到的祖先節點編號),有了這兩個資料,那麼根據我們上面的演算法我們知道如果low[i]>=num
[cur](i是cur的子節點),那麼也就是說i沒法回到祖先,所以說cur應該是割點

三.資料

n個點m個邊,無向圖

6 7

1 3

1 4

4 2

3 2

2 5

2 6

5 6

//
//  main.cpp
//  圖的割點
//
//  Created by 張嘉韜 on 16/8/29.
//  Copyright © 2016年 張嘉韜. All rights reserved.
//

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=1000;
int min(int a,int b)
{
    if(a<b) return a;
    else return b;
}
int map[maxn][maxn],n,m,x,y,root,flag[maxn],indx,num[maxn],low[maxn];
void dfs(int cur,int father)
{
    int child=0;
    indx++;
    num[cur]=indx;
    low[cur]=indx;
    for(int i=1;i<=n;i++)
    {
        if(map[cur][i]==1)
        {
            if(!num[i])
            {
                dfs(i,cur);// 子節點就去dfs()
                low[cur]=min(low[cur],low[i]);
                if(cur!=root&&low[i]>=num[cur]) flag[cur]=1;
                if(cur==root&&child==2) flag[cur]=1;//雖然未遍歷完但是如果有兩個兩個子節點了那麼一定就是割點。
            }
            else if(num[i]&&i!=father)
                low[cur]=min(num[i],low[cur]);
        }
    }
}
int main(int argc, const char * argv[]) {
    freopen("/Users/zhangjiatao/Documents/暑期訓練/input.txt","r",stdin);
    memset(map,0,sizeof(map));
    memset(flag,0,sizeof(flag));
    memset(num,0,sizeof(num));
    memset(low,0,sizeof(low));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        map[x][y]=1;
        map[y][x]=1;
    }
    root=1;
    indx=0;
    dfs(1,root);
    for(int i=1;i<=n;i++) cout<<num[i]<<" ";
    cout<<endl;
    for(int i=1;i<=n;i++) cout<<low[i]<<" ";
    cout<<endl;
    for(int i=1;i<=n;i++)
        if(flag[i]) printf("%d\n",i);
    return 0;
}