• POJ 3352 缩点 + 边双连通图


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

    题目大意及分析:

      题目我看了很多遍,没有看懂,关于至少添加多少边使得图双连通我没有想出来怎么做,直接看题解的,附一个好的题解:

      http://blog.csdn.net/lyy289065406/article/details/6762370

    PS:

      不得不说这题让我对一些概念有更深的理解。

      本题,只需要保证每两个点之间至少有两条路径,但是求出来的未必是双连通图,比如:

      5  4

      1  2

      2  3

      2  4

      2  5

      结果是2,但是加2条边后不是双连通图。

      所以这个题解我把标题写成了 缩点+ 边双连通图。

      我们必须要知道有种东西叫: 边双连通。

      我们常说的双连通分量是指不含割点的子图,割边(桥)连接的不一定是双连通分支(分量)。

      关于最后上面链接提到的那个结论公式,我在Beyond the Void大神博客里找到了一个解释: 

    统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。则至少在树上添加(leaf+1)/2条边,就能使树达到边二连通,所以至少添加的边数就是(leaf+1)/2。具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

    代码:

    poj3352
     1 /*3352    Accepted    292K    110MS    C++    2205B    2012-06-10 16:59:26*/
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <iostream>
     6 #include <algorithm>
     7 #include <vector>
     8 using namespace std;
     9 
    10 #define mpair make_pair
    11 #define pii pair<int,int>
    12 #define MM(a,b) memset(a,b,sizeof(a));
    13 typedef long long lld;
    14 typedef unsigned long long u64;
    15 template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
    16 template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}
    17 #define maxn 1020
    18 
    19 int n,m;
    20 vector<int> adj[maxn];
    21 
    22 int Bcnt, Index, Top;
    23 int low[maxn], dfn[maxn], sta[maxn], belong[maxn];
    24 bool vis[maxn];
    25 void Init_tarjan(){
    26     Bcnt= Index= Top= 0;
    27     for(int i=1;i<=n;++i) low[i]= dfn[i]= vis[i]= 0;
    28 }
    29 void Tarjan(int u,int fa){
    30     low[u]= dfn[u]= ++Index;
    31     sta[++Top]= u;
    32     vis[u]= 1;
    33     for(int i=0;i<adj[u].size();++i){
    34         int v= adj[u][i];
    35         if( v==fa ) continue;
    36 
    37         if( !dfn[v] ){
    38             Tarjan( v, u );
    39             up_min( low[u], low[v] );
    40         }
    41         else if( vis[v] )
    42             up_min( low[u], dfn[v] );
    43     }
    44     if( low[u]==dfn[u] ){
    45         ++Bcnt;
    46         int v;
    47         do{
    48             v= sta[Top--];
    49             vis[v]= 0;
    50             belong[v]= Bcnt;
    51         }while( u!=v );
    52     }
    53 }
    54 
    55 int degree[maxn];
    56 void dfs(int u){
    57     vis[u]= 1;
    58     for(int i=0;i<adj[u].size();++i){
    59         int v= adj[u][i];
    60         if( !vis[v] ){
    61             if( belong[u]!=belong[v] ){
    62                 ++degree[ belong[v] ];
    63                 ++degree[ belong[u] ];
    64             }
    65             dfs(v);
    66         }
    67     }
    68 }
    69 
    70 int main()
    71 {
    72     //freopen("poj3352.in","r",stdin);
    73     while( cin>>n>>m ){
    74         int i,x,y;
    75         for(i=1;i<=n;++i) adj[i].clear();
    76         while( m-- ){
    77             scanf("%d%d", &x, &y);
    78             adj[x].push_back(y);
    79             adj[y].push_back(x);
    80         }
    81 
    82         Init_tarjan();
    83         Tarjan( 1, 1 ); ///
    84 
    85         if( 1==Bcnt ){
    86             puts("0"); continue;
    87         }
    88 
    89         fill( degree, degree+1+Bcnt, 0 );
    90         MM( vis, 0 );
    91         dfs( 1 );
    92 
    93         int tot= 0;
    94         for(i=1;i<=Bcnt;++i)
    95             if( degree[i]==1 ) tot++;
    96         printf("%d\n",(tot+1)/2 );
    97     }
    98 }

     

      

  • 相关阅读:
    openmp
    opencv 读写矩阵
    string to const char*
    c++ string to number
    HDU 1520 Anniversary Party
    ZOJ 1003 Crashing Balloon
    HDU 4171 Paper Route
    ZOJ 2067 White Rectangles
    TOJ 1690 Cow Sorting (置换群)
    TOJ 2814 Light Bulb
  • 原文地址:https://www.cnblogs.com/yimao/p/2544027.html
Copyright © 2020-2023  润新知