• UESTC_方老师和农场 2015 UESTC Training for Graph Theory<Problem L>


    L - 方老师和农场

    Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
     

    方老师重新开了一家农场,农场一共有N个节点和M条双向边,但是有一个很大的问题就是有比如一个农场A到达农场B只有一条路径,问至少添加多少条边使得任意两个农场之间的路径多于一条。

    Input

    • 多组数据,EOF结束。
    • 1行:NM
    • 2到第M+1行:每一行2个数UiVi,表示UiVi之间有一条边。

    Output

    一行一个数表示至少需要添加多少条边。

    Sample input and output

    Sample InputSample Output
    7 7
    1 2
    2 3
    3 4
    2 5
    4 5
    5 6
    5 7
    2

    Hint

    N100000M100000

    解题思路:

    我们先考虑原图连通的情况

    首先跑一遍图,求出所有的桥,之后跑出边双连通分量数目.

    将边双连通分量看成一个点.

    之后我们考虑整个图,必然成了一棵树.

    证明:

     假设将边双连通分量看成一个点后图不是树,必然存在两个儿子之间连有边,这样就构成了边双连通,显然不合法,故命题正确.

     

    <B,C>之间不可能有边,否则构成了边双连通.

    之后我们将问题转换为了树上至少连多少条边,使得树上任意两点的路径条数多于两条?

    这样问题就很容易解了.

    设树上的叶子有 N 个

    If N ∈ (2 * k ) , ans = N / 2;

    Else ans = ( N + 1 ) / 2

    综合下得 ans = (N + 1 ) / 2;

    为什么这样是对的呢?,我们将树上非叶的结点看成一个大圆圈,之后叶子,两两配对(找不到就自己和自己配),配对的顺序是第 x 个,和第 n – x + 1个,如图:

     

    之后我们考虑,若原图不连通,如何求解?

    还是看成大圆圈加几个根,把所有的叶子数加起来当成 N 就可以了.

    这里有点要注意,我们给一旦连了一条边,其实我们就等于给大圆圈连了一条边了

    <夜深了,就不证明了>

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <set>
    #define pb push_back
    
    //#define localtest
    
    
    using namespace std;
    const int maxn = 1e5 + 50;
    int n,m,new_time[maxn],low[maxn],T,tot,degree[maxn],number[maxn];
    bool use[maxn];
    
    typedef pair<int,int> Etype;
    set<Etype>spj;
    
    typedef struct Edge
    {
      int v,isbridge;
      Edge(const int &v)
       {
             this->v = v;
             isbridge = 0;
       }    
    };
    
    
    vector<Edge>E[maxn];
    
    
    
    int tarjan_dfs(int cur,int pre)
    {
       new_time[cur] = low[cur] = T++;
       for(int i = 0 ; i < E[cur].size() ; ++ i)
        {
             int nextnode = E[cur][i].v;
             if (!new_time[nextnode]) //树边 
              {
                   int lowv = tarjan_dfs(nextnode,cur);
                   if (lowv > new_time[cur])
                    {
                        E[cur][i].isbridge = 1;
                        #ifdef localtest
                         cout << cur << " - " << nextnode << " is a bridge " << endl;
                        #endif
                        use[cur] = true , use[nextnode] = true;
                     }
                    low[cur] = min(low[cur],lowv); // updata
              }
            else if(new_time[nextnode] < new_time[cur] && nextnode != pre) //反向边 
              low[cur] = min(low[cur],low[nextnode]);
        }
      return low[cur];
    }
    
    
    
    int main(int argc,char *argv[])
    {
      while(~scanf("%d%d",&n,&m))
       {
             spj.clear();
             for(int i = 1 ; i <= m ; ++ i)
              {
                    int u,v;
                    scanf("%d%d",&u,&v);
                    if (u > v)
                     swap(u,v);
                    Etype temp(u,v);
                    if (spj.count(temp))
                     continue;
                    else
                     spj.insert(temp);    
                    E[u].pb(Edge(v)) , E[v].pb(Edge(u));
              }
             memset(new_time,0,sizeof(new_time));
             memset(number,0,sizeof(number));
             memset(use,false,sizeof(use));
             memset(degree,0,sizeof(degree));
             T = 1;
             for(int i = 1 ; i <= n ; ++ i)
              if (!new_time[i])
               tarjan_dfs(i,0); //跑割桥 
             for(int i = 1 ; i <= n ; ++ i)
              {
                 for(int j = 0 ; j < E[i].size() ; ++ j)
                {
                    int nextnode = E[i][j].v;
                    if (low[i] != low[nextnode]) //缩点 
                     {
                         degree[low[i]] ++ ;
                         degree[low[nextnode]] ++ ;
                     }
                }    
           }
          int leaf = 0;
          for(int i = 1 ; i <= n ; ++ i)
           if (degree[i]  == 2)
            leaf++;
          printf("%d
    ",(leaf+1)/2);
             for(int i = 1 ; i <= n ; ++ i)
              E[i].clear();
       }
      return 0;
    }

     

  • 相关阅读:
    (转)位置无关码、位置有关码
    【转载】PM为什么会存在?怎么存在?
    战略是什么?3-互联网产品行业以及竞争对手分析
    【转载】2014,要格外留意这7大投资机会——哈继铭 {key:人口红利、房价、社会结构、贸易逆差}
    2014年书单-30本
    产品经理要树立战略意识——战略是什么2(谈国家限制支付宝的战略分析)
    产品经理要树立战略意识——战略是什么1
    【转载】产品经理入门案例分析——锤子手机策略
    javascript设计模式-工厂模式
    javascript设计模式-单例模式
  • 原文地址:https://www.cnblogs.com/Xiper/p/4570670.html
Copyright © 2020-2023  润新知