• POJ 3694 Network(并查集缩点 + 朴素的LCA + 无向图求桥)题解


    题意:给你一个无向图,有q次操作,每次连接两个点,问你每次操作后有几个桥

    思路:我们先用tarjan求出所有的桥,同时我们可以用并查集缩点,fa表示缩点后的编号,还要记录每个节点父节点pre。我们知道,缩点后形成一棵树,所有边都是桥,连接两点必会成环,环上任意边都不是桥。所以连点后,我们把两个点一步一步往上走,如果往上走之后发现fa不一样,说明走过了一条桥,那么合并fa,桥数量-1。

    代码:

    #include<set>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    typedef long long ll;
    const int maxn = 100000 + 10;
    const int seed = 131;
    const ll MOD = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    int head[maxn], dfn[maxn], low[maxn], vis[maxn], fa[maxn], pre[maxn], tot, index, ans;
    struct Edge{
        int to, next;
    }e[maxn << 2];
    void addEdge(int u, int v){
        e[tot].to = v;
        e[tot].next = head[u];
        head[u] = tot++;
    }
    int find(int x){
        return fa[x] == x? x : fa[x] = find(fa[x]);
    }
    void Union(int u, int v){
        int fx = find(u);
        int fy = find(v);
        if(fx != fy){
            fa[fx] = fy;
        }
    }
    void tarjan(int u, int Fa){
        vis[u] = 1;
        dfn[u] = low[u] = ++index;
        pre[u] = Fa;
        for(int i = head[u]; i != -1; i = e[i].next){
            int v = e[i].to;
            if(!dfn[v]){
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
                if(low[v] > dfn[u]){
                    ans++;
                }
                else{
                    Union(u, v);
                }
            }
            else if(v != Fa){
                low[u] = min(low[u], dfn[v]);
            }
        }
    }
    void Move(int x){
        int fx = find(x);
        int fy = find(pre[x]);
        if(fx != fy){
            fa[fx] = fy;
            ans--;
        }
    }
    void LCA(int u, int v){
        while(dfn[u] > dfn[v]){
            Move(u);
            u = pre[u];
        }
        while(dfn[v] > dfn[u]){
            Move(v);
            v = pre[v];
        }
        while(u != v){
            Move(u);
            Move(v);
            u = pre[u];
            v = pre[v];
        }
    }
    void init(){
        tot = index = ans = 0;
        memset(head, -1, sizeof(head));
        memset(vis, 0, sizeof(vis));
        memset(dfn, 0, sizeof(dfn));
    }
    int main(){
        int n, m, Case = 1;
        while(scanf("%d%d", &n, &m) && n + m){
            init();
            int u, v;
            for(int i = 0; i < m; i++){
                scanf("%d%d", &u, &v);
                addEdge(u, v);
                addEdge(v, u);
            }
            for(int i = 0; i <= n; i++)
                fa[i] = i;
            tarjan(1, 1);
            int q;
            scanf("%d", &q);
            printf("Case %d:
    ", Case++);
            while(q--){
                scanf("%d%d", &u, &v);
                if(find(u) != find(v)){
                    LCA(u, v);
                }
                printf("%d
    ", ans);
            }
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    封装缓动动画函数
    封装动画函数-匀速运动
    实现产品图片的放大镜效果:
    仿淘宝侧边栏滚动案例:
    页面被卷去的头部兼容性解决方案
    简单发送短信倒计时案例
    Echarts 版本的那些坑
    json变量作键名
    媒体查询那些事儿
    mac 强制关闭指定端口
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9733581.html
Copyright © 2020-2023  润新知