• [kuangbin带你飞]专题九 连通图E POJ 3177 Redundant Paths


    这个题最开始我想的是,直接缩点求双连通分量,连接这些双联通分量不就行了吗?

    但是其实是不对的,双连通内部双联通,我们如果任意的连接一条边在这些双联通分量之间,他们之间有没有桥其实并不知道。

    我应该是求缩点以后的叶子节点的个数,因为叶子节对于其本身来说,只有一条桥于其相连,我们可以连接两个叶子节点。那么这个两个区域就合成了一个双联通分量区域。同时为了减少边的使用,我们可以连接两个都是叶子节点的点。最后+1,剩下一个也应该连接。这样就能非常容易的算出把图变成双连通,所需要的边的数目。

    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<stdio.h>
    using namespace std;
    const int N = 1e4+5,M = 1e5+5;
    int head[N],Next[M],ver[M],low[M],dfn[M],stack[M];
    int block;
    int belong[M],deg[M];
    bool brige[M],ins[M];
    int c[M],dcc,top;
    int tot,n,m,num,cnt;
    void add(int x,int y)
    {
        ver[++tot]=y;
        Next[tot]=head[x];
        head[x]=tot;
    }
    void tarjan(int u,int pre)
    {
        int v;
        dfn[u]=low[u]=++num;
        stack[++top]=u;
        ins[u]=1;
        for (int i=head[u]; i; i=Next[i])
        {
             v=ver[i];
            if (v==pre)continue;
            if (!dfn[v])
            {
                tarjan(v,u);
                low[u]=min(low[u],low[v]);
                if (low[v]>dfn[u])
                {
                    brige[i]=1;//标记为桥
                    brige[i^1]=1;
                    cnt++;
                }
            }
            else low[u]=min(low[u],dfn[v]);
        }
        if (low[u]==dfn[u]){//如果当前节点是一个根节点 也就是说我们DFS完了这个连通分量
            cnt++;
            do
            {
                v=stack[top--];//把这个连通分量里面的所有点都拿出来
                ins[v]=0;
                c[v]=cnt;//标记上所在的连通分量
            }while(u!=v);
        }
    }
    void init(){
       memset(Next,0,sizeof(Next));
       memset(low,0,sizeof(low));
       memset(brige,0,sizeof(brige));
       memset(head,0,sizeof(head));
       memset(ver,0,sizeof(ver));
       memset(dfn,0,sizeof(dfn));
       memset(c,0,sizeof(c));
       tot=1;
       cnt=0;
       num=0;
       dcc=0;
       top=0;
    }
    int main()
    {
        int u,v;
        while(~scanf("%d%d",&n,&m))
        {
            init();
            for (int i=1; i<=m; i++)
            {
                scanf("%d%d",&u,&v);
                add(u,v);
                add(v,u);
            }
            for (int i=1;i<=n;i++){
                if (!dfn[i]){
                    tarjan(i,i);
                }
            }
            for (int i=1;i<=n;i++){
                for (int j=head[i];j;j=Next[j])
                {
                      if (brige[j])   //缩点后把桥两边的缩点的度++
                        deg[c[i]]++;
                }
            }
            int ans=0;
            for (int i=1;i<=cnt;i++){
                if (deg[i]==1){//我们找出缩点后度为1的点,也就是叶子节点,
                    ans++;
                }
            }
            printf("%d
    ",(ans+1)/2);//那么把图连接成双联通分量的所需边=(缩点后叶子节点的个数+1)/2
            //因为很简单 我把叶子节点两两连接起来,那么这样消耗的边也就是最少的。这样我们就能让图
            //变成双联通的
         }
        return 0;
    }
    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    英语长难句
    服务器部署 halo博客项目
    11月迟来的总结
    10月总结
    9月总结
    python根据字符串导入模块
    RestFul(番外):类视图更适合restful
    Django-基础 Meta自定义
    (垃圾代码)修改同目录下面的xml文件标签数值
    Django-templatetags设置(在templates中使用自定义变量)
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/11229408.html
Copyright © 2020-2023  润新知