zoukankan      html  css  js  c++  java
  • POJ 3352 (边双连通分量)

    题目链接http://poj.org/problem?id=3352

    题目大意:一个连通图中,至少添加多少条边,使得删除任意一条边之后,图还是连通的。

    解题思路

    首先来看下边双连通分量的定义:

    如果任意两点至少存在两条“边不重复”的路径,那么说这个图是边双连通的。

    那么本题中,删除任意一条边,就可以看作是毁掉一条路径,那么只要至少还存在一条路径即可。

    也就是说,转化成,求加最少的边,使这个图边双连通。

    判断边双连通有两个方法:

    ①【局限性】编号借助low数组,如果low[u]!=low[v],就代表这两个点在不同双连通分量中。

    这种方法有些小Bug,主要Bug在邻接表这样的不支持重边的数据结构上,如果有重边存在,

    那么即使low[u]!=low[v],u和v也有可能存在于同一个连通分量中。

    所以推荐使用链式前向星。

    ②Tarjin时借助并查集,由于桥(删除之后图就不连通的边)不属于任何双连通分量,所以在Tarjin时,把不是桥的边的u,v并在一起,

    表示u,v在同一个双连通分量里,进行缩点。

    下面来看一条结论:

    若要使得任意一棵树,在增加若干条边后,变成一个双连通图,那么

    至少增加的边数 =( 这棵树总度数为1的结点数 + 1 )/ 2。

    这样,只需要统计一下缩点之后每个点的度数即可。

    ①方法low[u]中存的就是缩点编点,②方法并查集find之后也是缩点编号,degree[编号]记录度数。

    注意,由于本题是无向图,对于每条边,只需degree[low[u]]++即可,不用管v。否则每个点的degree要除以2.

    最后ans=(leaf+1)/2.

    #include "cstdio"
    #include "cstring"
    #include "iostream"
    using namespace std;
    #define maxn 2005
    struct Edge
    {
        int to,next;
    }e[maxn*2];int pre[maxn],dfs_clock,low[maxn],degree[maxn],head[maxn],tol;
    void addedge(int u,int v)
    {
        e[tol].to=v;
        e[tol].next=head[u];
        head[u]=tol++;
    }
    int dfs(int u,int fa)
    {
        int lowu=pre[u]=++dfs_clock;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            if(!pre[v])
            {
                int lowv=dfs(v,u);
                lowu=min(lowu,lowv);
            }
            else if(pre[v]<pre[u]&&v!=fa) lowu=min(lowu,pre[v]);
        }
        return low[u]=lowu;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        int n,m,u,v;
        while(~scanf("%d%d",&n,&m))
        {
            memset(head,-1,sizeof(head));
            memset(pre,0,sizeof(pre));
            memset(low,0,sizeof(low));
            memset(degree,0,sizeof(degree));
            dfs_clock=0;tol=0;
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&u,&v);
                addedge(u,v);
                addedge(v,u);
            }
            for(int i=1;i<=n;i++) if(!pre[i]) dfs(i,-1);
            for(int u=1;u<=n;u++)
            {
                for(int i=head[u];i!=-1;i=e[i].next)
                {
                    int v=e[i].to;
                    if(low[u]!=low[v]) degree[low[u]]++;
                }
            }
            int leaf=0;
            for(int i=1;i<=n;i++)
                if(degree[i]==1) leaf++;
            printf("%d
    ",(leaf+1)/2);
        }
    }
  • 相关阅读:
    在WCF中使用Flag Enumerations
    WCF开发教程资源收集
    [转]WCF 4 安全性和 WIF 简介
    Asp.Net Web API 2 官网菜鸟学习系列导航[持续更新中]
    Asp.Net Web API 2第十八课——Working with Entity Relations in OData
    Asp.Net Web API 2第十七课——Creating an OData Endpoint in ASP.NET Web API 2(OData终结点)
    Asp.Net Web API 2第十六课——Parameter Binding in ASP.NET Web API(参数绑定)
    Asp.Net Web API 2第十五课——Model Validation(模型验证)
    函数 生成器 生成器表达式
    函数的进阶
  • 原文地址:https://www.cnblogs.com/neopenx/p/4065220.html
Copyright © 2011-2022 走看看