uestc 方老师和农场

转自http://www.cnblogs.com/whatbeg/p/3765624.html

首先将原图中的连通分量缩点,一定可以将原图缩成一棵树的形式,然后统计这棵树的叶子节点个数,答案就是(leaf+1)/2。这里不再证明,可以画个图看一下。

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

怎么统计呢?用并查集缩点,可以知道,缩点后留下的边全部是原图的桥,这是我们可以用Tarjan求出原图的所有桥,然后枚举每条桥,桥两端的点度数分别+1,就可以求出每个点(缩点后的点)的度数了,找出度数为1的即为叶子节点。

怎么用Tarjan求桥呢?根据Tarjan算法性质可知,若low[v]>dfn[u],则边(u,v)为桥(v被封死在子树内)

如图,若low[v]>dfn[u],则v被封死在u的子树内,删除点u,或者删除边(u,v),都将使v与u的祖先w不连通。

关于Tarjan求桥可见:http://hi.baidu.com/lydrainbowcat/item/f8a5ac223e092b52c28d591c

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<string>
  6 #include<queue>
  7 #include<algorithm>
  8 #include<map>
  9 #include<iomanip>
 10 #include<climits>
 11 #include<string.h>
 12 #include<cmath>
 13 #include<stdlib.h>
 14 #include<vector>
 15 #include<stack>
 16 #define INF 1000000007
 17 #define MAXN 40010
 18 #define Mod 1000007
 19 #define N 10010
 20 #define NN 30
 21 #define sigma_size 3
 22 const int maxn = 6e5 + 10;
 23 using namespace std;
 24 typedef long long LL;
 25 
 26 struct Bridge {
 27     int u, v;
 28 }bg[2*N];
 29 
 30 vector<int> G[N];
 31 int vis[N], low[N], dfn[N], Time;
 32 int fa[N], deg[N];
 33 int n, m, cnt;
 34 int u, v;
 35 
 36 int findset(int x) 
 37 {
 38     return fa[x] = fa[x] == x ? x : findset(fa[x]);
 39 }
 40 
 41 void init()
 42 {
 43     for (int i = 0; i <= n; ++i) {
 44         G[i].clear();
 45         fa[i] = i;
 46     }
 47     memset(dfn,0,sizeof(dfn));
 48     memset(low,0,sizeof(low));
 49     memset(vis,0,sizeof(vis));
 50     memset(deg, 0, sizeof(deg));
 51     cnt = Time = 0;
 52     for (int i = 0; i < m;++ i) {
 53         cin >> u >> v;
 54         G[u].push_back(v);
 55         G[v].push_back(u);
 56     }
 57 }
 58 
 59 void Tarjan(int u, int father)
 60 {
 61     low[u] = dfn[u] = ++Time;
 62     vis[u] = 1;
 63     for (int i = 0; i < G[u].size(); ++i) {
 64         int v = G[u][i];
 65         if (v == father) continue;
 66         if (!vis[v]){
 67             Tarjan(v, u);
 68             low[u] = min(low[u], low[v]);
 69             if (low[v] > dfn[u]){  //u->v为桥
 70                 bg[cnt].u = u;
 71                 bg[cnt].v = v;
 72                 cnt++;
 73             }
 74             else {                   //否则u,v同属一个连通分量,合并
 75                 int fx = findset(u);
 76                 int fy = findset(v);
 77                 if (fx != fy)
 78                     fa[fx] = fy;
 79             }
 80         }
 81         else {
 82             low[u] = min(low[u],dfn[v]);
 83         }
 84     }
 85 }
 86 
 87 int main()
 88 {
 89     while (cin >> n >> m) {
 90         init();
 91         Tarjan(1,-1);
 92         for (int i = 0; i < cnt; ++i) {
 93             int fx = findset(bg[i].u);
 94             int fy = findset(bg[i].v);
 95             deg[fx]++;
 96             deg[fy]++;
 97         }
 98         int leaf = 0;
 99         for (int i = 1; i <= n; ++i)
100             if(deg[i] == 1) leaf++;
101         cout << (leaf + 1) / 2 << endl;
102     }
103     //system("pause");
104     return 0;
105 }

 

posted @ 2015-02-28 17:45  UsedRose  阅读(204)  评论(0编辑  收藏  举报