码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-06-12 06:22:41      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:

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\n",(leaf+1)/2);
         for(int i = 1 ; i <= n ; ++ i)
          E[i].clear();
   }
  return 0;
}

 

 

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

标签:

原文地址:http://www.cnblogs.com/Xiper/p/4570670.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!