• poj3352 Road Construction & poj3177 Redundant Paths (边双连通分量)题解


    题意:有n个点,m条路,问你最少加几条边,让整个图变成边双连通分量。

    思路:缩点后变成一颗树,最少加边 = (度为1的点 + 1)/ 2。3177有重边,如果出现重边,用并查集合并两个端点所在的缩点后的点。

    代码:

    /*3352*/
    #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 = 5000 + 10;
    const int seed = 131;
    const ll MOD = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    struct Edge{
        int u, v, next;
    }edge[maxn << 1];
    int index, scc_cnt, tot;    //scc_cnt记录SCC
    int dfn[maxn], low[maxn], sccno[maxn], in[maxn], head[maxn];
    stack<int> s;
    void addEdge(int u, int v){
        edge[tot].v = v;
        edge[tot].u = u;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    void tarjan(int u, int pre){
        dfn[u] = low[u] = ++index;
        s.push(u);
        for(int i = head[u]; i != -1; i = edge[i].next){
            int v = edge[i].v;
            if(!dfn[v]){
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
            }
            else if(v != pre){
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(dfn[u] == low[u]){
            scc_cnt++;
            int a;
            while(1){
                a=s.top();
                s.pop();
                sccno[a] = scc_cnt;
                if(a == u) break;
            }
        }
    }
    
    int main(){
        int n, m;
        scanf("%d%d", &n, &m);
        index = scc_cnt = tot = 0;
        while(!s.empty()) s.pop();
        memset(head, -1, sizeof(head));
        memset(dfn, 0, sizeof(dfn));
        memset(sccno, 0, sizeof(sccno));
        for(int i = 0; i < m; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            addEdge(u, v);
            addEdge(v, u);
        }
        for(int i = 1; i <= n; i++){
            if(!dfn[i])
                tarjan(i, 0);
        }
        memset(in, 0, sizeof(in));
        for(int i = 0; i < tot; i += 2){
            int u = edge[i].u, v = edge[i].v;
            if(sccno[u] != sccno[v]){
                in[sccno[u]]++;
                in[sccno[v]]++;
            }
        }
        int cnt = 0;
        for(int i = 1; i <= scc_cnt; i++){
            if(in[i] == 1) cnt++;
        }
        printf("%d
    ", (cnt + 1) / 2);
        return 0;
    }
    /*3177*/
    #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 = 5000 + 10;
    const int seed = 131;
    const ll MOD = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    struct Edge{
        int u, v, next;
    }edge[maxn << 1];
    int index, scc_cnt, tot;    //scc_cnt记录SCC
    int dfn[maxn], low[maxn], sccno[maxn], in[maxn], head[maxn];
    stack<int> s;
    map<int, int> mp[maxn];
    int Find(int x){
        return sccno[x] == x? x : sccno[x] = Find(sccno[x]);
    }
    void addEdge(int u, int v){
        edge[tot].v = v;
        edge[tot].u = u;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    void tarjan(int u, int pre){
        dfn[u] = low[u] = ++index;
        s.push(u);
        for(int i = head[u]; i != -1; i = edge[i].next){
            int v = edge[i].v;
            if(!dfn[v]){
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
            }
            else if(v != pre){
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(dfn[u] == low[u]){
            scc_cnt++;
            int a;
            while(1){
                a=s.top();
                s.pop();
                sccno[a] = u;
                if(a == u) break;
            }
        }
    }
    
    int main(){
        int n, m;
        scanf("%d%d", &n, &m);
        index = scc_cnt = tot = 0;
        while(!s.empty()) s.pop();
        memset(head, -1, sizeof(head));
        memset(dfn, 0, sizeof(dfn));
        memset(sccno, 0, sizeof(sccno));
        for(int i = 0; i < m; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            addEdge(u, v);
            addEdge(v, u);
        }
        for(int i = 1; i <= n; i++){
            if(!dfn[i])
                tarjan(i, 0);
        }
        for(int i = 1; i <= n; i++) mp[i].clear();
        memset(in, 0, sizeof(in));
        for(int i = 0; i < tot; i += 2){
            int u = edge[i].u, v = edge[i].v;
            if(u > v) swap(u, v);
            mp[u][v]++;
            if(mp[u][v] == 2){
                int fx = Find(u), fy = Find(v);
                if(fx != fy){
                    sccno[fx] = fy;
                }
            }
        }
        for(int i = 0; i < tot; i += 2){
            int u = edge[i].u, v = edge[i].v;
            int fx = Find(u), fy = Find(v);
            if(fx != fy){
                in[fx]++;
                in[fy]++;
            }
        }
        int cnt = 0;
        for(int i = 1; i <= n; i++){
            if(sccno[i] == i && in[i] == 1) cnt++;
        }
        printf("%d
    ", (cnt + 1) / 2);
        return 0;
    }
  • 相关阅读:
    Message Flood SDUT 1500
    SDUT1482——二元多项式
    SDUT—2057 模拟题
    Eight(bfs+全排列的哈希函数)
    Pick-up sticks(判断两条线段是否相交)
    poj 1265 Area(pick定理)
    poj 2503 Babelfish(字典树哈希)
    poj 3007 Organize Your Train part II(静态字典树哈希)
    Surprising Strings(map类)
    Strange Way to Express Integers (一般模线性方程组)
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9781332.html
Copyright © 2020-2023  润新知