无向图求割点和割边——Tarjan算法

2018-12-07  本文已影响0人  Herixth

程序展示(c++)

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

const int maxn = 1e3 + 10;
const int maxm = 1e6 + 10;

int tst;    // timestamp
int N, M;   // 顶点数N,边数M

struct Edge {
    int from, to;
    Edge(int f = 0, int t = 0):
        from(f), to(t) { }
    ~Edge() { }
};

// adj-list undirected graph
// idx -> even with compone idx + 1.
vector<Edge> edges;    //所有边的集合
vector<int> ver[maxn]; //记录每一个顶点出发的边在edges中的索引
int dfn[maxn];
int low[maxn];

vector<int> verCut;    //割点集
vector<Edge> edgeCut;  //割边集

/**
 * @brief 读取数据,以邻接表方式储存,因为是无向图需要一条边存两次
 *        第1行输入N和M表示图的顶点数和边数
 *        接下来第2到第M + 1行输入from和to表示无向图的一条边的两个顶点.
 */
void readData() {
    cin >> N >> M;
    for (int inc = 0; inc < M; inc ++) {
        int from = 0, to = 0;
        cin >> from >> to;
        ver[from].push_back(edges.size());
        edges.push_back(Edge(from, to));
        ver[to].push_back(edges.size());
        edges.push_back(Edge(to, from));
    }
}

/**
 * @brief DFS回溯上标签
 * @param curr_ver 当前顶点的编号
 * @param fa_ver   当前顶点的父亲编号,根节点父亲设为-1
 */
void labelling(int curr_ver = 0, int fa_ver = -1) {
    dfn[curr_ver] = low[curr_ver] = ++tst;  //初始化dfn和low
    for (vector<int>::iterator iter = ver[curr_ver].begin();
        iter != ver[curr_ver].end(); iter ++) {
        if (edges[*iter].to == fa_ver)
            continue;
        if (!low[edges[*iter].to]) {
            labelling(edges[*iter].to, curr_ver);
        }
        low[curr_ver] = min(low[curr_ver], low[edges[*iter].to]);
    }
}

/**
 * @brief 收集统计割点及割边
 */
void collect(int curr_ver = 0, int fa_ver = -1) {
    tst++;
    bool is_vercut = false;
    for (vector<int>::iterator iter = ver[curr_ver].begin();
         iter != ver[curr_ver].end(); iter++) {
        if (edges[*iter].to == fa_ver || dfn[edges[*iter].to] != tst + 1)
            continue;
        collect(edges[*iter].to, curr_ver);
        int sub = low[edges[*iter].to] - dfn[curr_ver];
        is_vercut = (sub >= 0);
        if (sub > 0) {
            edgeCut.push_back(Edge(curr_ver, edges[*iter].to));
        }
    }
    if (is_vercut) {
        verCut.push_back(curr_ver);
    }
}

/**
 * @brief tarjan算法,包含两个子函数,调用函数前需要将时间戳重置
 */
void tarjan() {
    tst = 0;
    labelling();

    tst = 0;
    collect();
}

void show() {
    cout << "vertex cut(s):" << endl;
    cout << "total: " << verCut.size() << endl;
    for (vector<int>::iterator iter = verCut.begin();
        iter != verCut.end(); iter ++) {
        cout << (*iter) << endl;
    }

    cout << "edge cut(s):" << endl;
    cout << "total: " << edgeCut.size() << endl;
    for (vector<Edge>::iterator iter = edgeCut.begin();
         iter != edgeCut.end(); iter ++) {
        cout << (*iter).from << " to " << (*iter).to << endl;
    }
}

int main() {
    //freopen("Tarjan.txt", "r", stdin);

    readData();

    tarjan();

    show();

    return 0;
}

/*****测试数据******
6 6
0 1
1 3
3 4
4 5
1 4
1 2
*******************/

上一篇下一篇

猜你喜欢

热点阅读