• POJ 3352 Road Construction (双连通缩点)


    题目大意:给定一个无向连通图,求至少需添加几条边,使得原图双连通(不存在桥)。

    分析:用tarjan算法找桥,将所有不是桥的边的端点用并查集合并,这题以前写过,至于为什么可以用并查集来合并,可以参考以前那篇博客

    需要注意的是,数据中有重边,在判桥时要注意。可以用一个矩阵存储边的数目,若某边数目大于1,则一定不是桥。

    View Code
    #include <stdio.h>
    #include <string.h>
    #define MIN(a,b) ((a)<(b)?(a):(b))
    #define N 1001
    #define M 2002
    int n,m,e;
    int g[N][N];
    int first[N],next[M],v[M];
    int dfn[N],low[N],id[N],cnt;
    int p[N];
    int d[N];
    void make_set()
    {
        for(int i=1;i<=n;i++)   p[i]=i;
    }
    int find_set(int i)
    {
        if(i^p[i])  p[i]=find_set(p[i]);
        return p[i];
    }
    void union_set(int i,int j)
    {
        i=find_set(i),j=find_set(j);
        if(i^j) p[j]=i;
    }
    void init()
    {
        e=0;
        memset(first,-1,sizeof(int)*(n+1));
        cnt=0;
        memset(dfn,0,sizeof(int)*(n+1));
        for(int i=1;i<=n;i++)   memset(g[i],0,sizeof(int)*(n+1));
    }
    void insert(int a,int b)
    {
        v[e]=b;
        next[e]=first[a];
        first[a]=e++;
        g[a][b]++;
    }
    void dfs(int a,int fa)
    {
        int i,b;
        dfn[a]=low[a]=++cnt;
        for(i=first[a];i!=-1;i=next[i])
        {
            b=v[i];
            if(dfn[b] && b!=fa)  low[a]=MIN(low[a],dfn[b]);
            else if(!dfn[b])
            {
                dfs(b,a);
                low[a]=MIN(low[b],low[a]);
                if(low[b]<=dfn[a] || g[a][b]>1)
                {
                    union_set(a,b);
                }
            }
        }
    }
    void solve()
    {
        int a,b,i,pi,k=0;
        dfs(1,0);
        memset(id,-1,sizeof(id));
        for(i=1;i<=n;i++)
        {
            pi=find_set(i);
            if(id[pi]==-1)  id[pi]=k++;
        }
        memset(d,0,sizeof(d));
        for(a=1;a<=n;a++)
        {
            for(i=first[a];i!=-1;i=next[i])
            {
                b=v[i];
                if(find_set(a)^find_set(b)) d[id[p[a]]]++,d[id[p[b]]]++;
            }
        }
        int ans=0;
        for(i=0;i<k;i++)    if(d[i]==2) ans++;
        printf("%d\n",(ans+1)/2);
    }
    int main()
    {
        int a,b;
        while(~scanf("%d%d",&n,&m))
        {
            init();
            make_set();
            while(m--)
            {
                scanf("%d%d",&a,&b);
                insert(a,b);
                insert(b,a);
            }
            solve();
        }
        return 0;
    }
  • 相关阅读:
    HDU 5188 zhx and contest(带限制条件的 01背包)
    Appium IOS 自己主动化測试初探
    微软自拍应用iOS版公布
    小白学开发(iOS)OC_ block数据类型(2015-08-08)
    从王自如和老罗的论战中我貌似懂得了点神马...
    trie树(字典树)
    分析深圳电信的新型HTTP劫持方式
    主要的约瑟夫环问题
    Linux下的led驱动程序,ok6410
    Android Support 包里到底有什么
  • 原文地址:https://www.cnblogs.com/algorithms/p/2610819.html
Copyright © 2020-2023  润新知