1. 程式人生 > >用Tarjan演算法求無向連通圖割點&&割邊

用Tarjan演算法求無向連通圖割點&&割邊

/**
    割點割邊挺好理解的,割點就是一個無向連通圖,把其中一個點
    挖掉剩下的圖不連通,割邊就是把一條邊砍掉不連通

    比如:有一個通訊網路,要求一顆炸彈,把這個通訊網路搞得不連通,問
    炸哪個點或哪條邊。

    Tarjan 演算法實現求割邊和割點很類似,不過還是有點不同,複雜度為O(N+M)

    下面用 <vector> 存邊寫下
*/

//求割點

#include <vector>
bool cut[nMax];   //cut[x] = ture 代表x 為割點
int dfn[nMax], low[nMax];  //dfn[x] x是當前層次,low[x] x是能到得的最低層次
//這兩個或許有點摸不著頭腦,不過沒關係,
//查下tarjan 自己畫畫差不多就能理解,tarjan只是個帥哥名字,沒那麼可怕
vector<int> adj[nMax];
int rt, rt_num; //起始節點和訪問此結點的次數,如果大於一則rt也為割點
//用於判斷起始結點是否也是割點
/**
    nMax為點的個數;
    rt選任意一點;
    rt_num = 0;
*/

void addEdge(int u, int v) {
    adj[u].push_back(v);
    adj[v].push_back(u);
}

void findcut(int dep, int u) {
    dfn[u] = low[u] = dep;
    for (int i=0; i<adj[u].size(); i++) {
        int v = adj[u][i];
        if (!dfn[v]) {
            findcut(dep+1, v);
            if (u == rt)
                rt_num++;
            else {
                low[u] = min(low[u], low[v]);
                if (low[v] >= dfn[u])
                    cut[u] = true;  //如果滿足這個條件則u 為割點

            }
        }
        else
            low[u] = min(low[u], dfn[v]);
    }
}

int main() {

    //初始化
    /**
        dfn = 0, cut = 0, rt_num = 0;
        adj[i].clear(); //對邊集進行清空
    */
    //建好圖後呼叫
    findcut(1, rt); //rt 任選 1 - n
    if (rt_num > 1)
        cut[rt] = true;

    //則cut 中為 true 的即為割點
    return 0;
}

//求割邊
void findcut(int dep, int u, int f) {
    dfn[u] = low[u] = dep;
    for (int i=0; i<adj[u].size(); i++) {
        int v = adj[u][i];
        if (!dfn[v]) {
            findcut(dep+1, v, u);

            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u])
                cut[u][v] = true;  //如果滿足這個條件則adj(u, v)為割邊

        }
        else if (f != v)
            low[u] = min(low[u], dfn[v]);
    }
}

//呼叫即可
    findcut(1, 1, 0);

/**
    還是那句話,模板都會用,關鍵在轉換
*/

 

收藏於 2012-01-09
來自於百度空間