割点,割边

割边

1.割边的定义:割边又叫做桥,如果去掉某条边会使得整张图的连通性变大,那么这条边就叫做割边。
2.求割边的思路:求割边我们使用tarjan算法,假设当前的算法不允许根据走返祖边用祖先的dfn值来更新自己的low值,那么如果有一个点有一个邻点的low值比他的dfn值还要小,就假设这两个点为u和v,那么如果 \(low[v] > low[u]\),那么就说明v如果不走(u, v)这条边的话,无论如何也走不到u前面的点了,那么边(u, v)很显然就是割点。
3.代码如下(这个代码是可以处理重边的,而且不用前向星)

void solve() {
    int n, m;cin >> n >> m;
    vvpi g(n + 1, vpi());
    for(int i = 1; i <= m; i++) {
        int u, v;cin >> u >> v;
        g[u].push_back({v, i << 1});
        g[v].push_back({u, i << 1 | 1});
    }
    vpi bridge;
    vi dfn(n + 1), low(n + 1);
    int tot = 0; 
    function<void(int, int)> tarjan = [&](int u, int fa) -> void {
        dfn[u] = low[u] = ++tot;
        for(auto [v, id] : g[u]) {
            if(id == (fa ^ 1)) continue;
            if(!dfn[v]) {
                tarjan(v, id);
                low[u] = min(low[u], low[v]);
                if(low[v] > dfn[u]) {
                    if(u < v) bridge.push_back({u, v});
                    else bridge.push_back({v, u});
                }
            } else low[u] = min(low[u], dfn[v]);
        }
    };
    tarjan(1, 0);
    sort(bridge.begin(), bridge.end());
    for(auto [i, j] : bridge) {
        cout << i << " " << j << "\n";
    }
}

割点

1.割点的定义:和割边相同,割点是去掉以后能增加图的连通性的点。
2.割点的求法:如果当前的点是割点并且不是根结点,那么直接根据 \(low[v] >= dfn[u]\) 就可以判断出某个点是不是割点。但是如果某个点是根节点,那么就需要两个这样的结点才能判断,为什么呢?因为如果有一个子节点满足上面那个条件,那么他的所有子节点其实都满足这个条件,但如果只有一个子节点的话,删掉一个其实连通性并没有增加。
3.代码如下:

void solve() {
    int n, m;cin >> n >> m;
    vvi g(n + 1, vi());
    for(int i = 1; i <= m; i++) {
        int u, v;cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    set<int> cut;
    vi dfn(n + 1), low(n + 1);
    int tot = 0;
    function<void(int, int)> tarjan = [&](int u, int root) -> void {
        dfn[u] = low[u] = ++tot;
        int child = 0, flag = 0;
        for(auto v : g[u]) {
            if(!dfn[v]) {
                tarjan(v, root);
                low[u] = min(low[u], low[v]);
                if(low[v] >= dfn[u]) {
                    child += 1;
                    if(u != root || child > 1) {
                        flag = 1;
                    }
                }
            } else low[u] = min(low[u], dfn[v]); 
        }
        if(flag) cut.insert(u);
    };
    for(int i = 1; i <= n; i++) {
        if(!dfn[i]) tarjan(i, i);
    }
    cout << cut.size() << "\n";
    for(auto i : cut) {
        cout << i << " ";
    }
    cout << "\n";
}
posted @ 2024-04-18 16:30  orzkeyhacker  阅读(24)  评论(0编辑  收藏  举报