zoukankan      html  css  js  c++  java
  • poj 3177 Redundant Paths(边双连通分量+缩点)

    链接:http://poj.org/problem?id=3177

    题意:有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走。现已有m条路,求至少要新建多少条路,使得任何两个牧场之间至少有两条独立的路。两条独立的路是指:没有公共边的路,但可以经过同一个中间顶点。

    分析:在同一个边双连通分量中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点。

    缩点后,新图是一棵树,树的边就是原无向图的桥。

    现在问题转化为:在树中至少添加多少条边能使图变为双连通图。

    结论:添加边数=(树中度为1的节点数+1)/2

    具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

    其实求边双连通分量和求强连通分量差不多,每次访问点的时候将其入栈,当low[u]==dfn[u]时就说明找到了一个连通的块,则栈内的所有点都属于同一个边双连通分量,因为无向图要见反向边,所以在求边双连通分量的时候,遇到反向边跳过就行了。

    网上有一种错误的做法是:因为每一个双连通分量内的点low[]值都是相同的,则dfs()时,对于一条边(u,v),只需low[u]=min(low[u],low[v]),这样就不用缩点,最后求度数的时候,再对于每条边(u,v)判断low[u]是否等于low[v],若low[u]!=low[v],则不是同一个边双连通分量,度数+1即可.....

    咋看之下是正确的,但是这种做法只是考虑了每一个强连通分量重只有一个环的情况,如果有多个环,则会出错。

    比如这组数据:

    16 21
    1 8
    1 7
    1 6
    1 2
    1 9
    9 16
    9 15
    9 14
    9 10
    10 11
    11 13
    11 12
    12 13
    11 14
    15 16
    2 3
    3 5
    3 4
    4 5
    3 6
    7 8

    答案是1,上面错误的做法是0

    大家自己画图慢慢研究吧。。。下面贴代码

    AC代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 const int N=5000+5;
     4 const int M=10000+5;
     5 
     6 struct EDGE
     7 {
     8     int v,next;
     9 }edge[M*2];
    10 int first[N],low[N],dfn[N],belong[N],degree[N],sta[M],instack[M];
    11 int g,cnt,top,scc;
    12 int min(int a,int b)
    13 {
    14     return a<b?a:b;
    15 }
    16 void AddEdge(int u,int v)
    17 {
    18     edge[g].v=v;
    19     edge[g].next=first[u];
    20     first[u]=g++;
    21 }
    22 void Tarjan(int u,int fa)
    23 {
    24     int i,v;
    25     low[u]=dfn[u]=++cnt;
    26     sta[++top]=u;
    27     instack[u]=1;
    28     for(i=first[u];i!=-1;i=edge[i].next)
    29     {
    30         v=edge[i].v;
    31         if(i==(fa^1))
    32             continue;
    33         if(!dfn[v])
    34         {
    35             Tarjan(v,i);
    36             low[u]=min(low[u],low[v]);
    37         }
    38         else if(instack[v])
    39             low[u]=min(low[u],dfn[v]);
    40     }
    41     if(dfn[u]==low[u])
    42     {
    43         scc++;
    44         while(1)
    45         {
    46             v=sta[top--];
    47             instack[v]=0;
    48             belong[v]=scc;
    49             if(v==u)
    50                 break;
    51         }
    52     }
    53 }
    54 int main()
    55 {
    56     int n,m,u,v,i,j;
    57     scanf("%d%d",&n,&m);
    58         g=cnt=top=scc=0;
    59         memset(first,-1,sizeof(first));
    60         memset(low,0,sizeof(low));
    61         memset(dfn,0,sizeof(dfn));
    62         memset(instack,0,sizeof(instack));
    63         memset(degree,0,sizeof(degree));
    64         for(i=0;i<m;i++)
    65         {
    66             scanf("%d%d",&u,&v);
    67             {
    68                 AddEdge(u,v);
    69                 AddEdge(v,u);
    70             }
    71         }
    72         for(i=1;i<=n;i++)
    73             if(!dfn[i])
    74                 Tarjan(1,-1);
    75         for(i=1;i<=n;i++)
    76         {
    77             for(j=first[i];j!=-1;j=edge[j].next)
    78             {
    79                 v=edge[j].v;
    80                 if(belong[i]!=belong[v])
    81                     degree[belong[i]]++;
    82             }
    83         }
    84         int sum=0;
    85         for(i=1;i<=n;i++)
    86             if(degree[i]==1)
    87                 sum++;
    88         int ans=(sum+1)/2;
    89         printf("%d
    ",ans);
    90     return 0;
    91 }
    View Code
  • 相关阅读:
    Linux常用命令
    杀死进程端口
    Spring boot项目的打包发布
    关于xshell和文件传输相关
    Windows10开发环境搭建
    Windows10设置系统参数
    windows10禁止更新
    Postgresql9.6基础使用(Windows 解压版)
    (转载)Thingsboard入门教程:本地环境搭建和源码编译安装,献给thingsboard编译失败的同学,教程不断完善中,文章最后是thingsboard常见编译失败的问题总结
    系统同时安装 Open JDK and Oracle JDK(Ubuntu16.04)
  • 原文地址:https://www.cnblogs.com/frog112111/p/3367039.html
Copyright © 2011-2022 走看看