UVA5135 Mining Your Own Business ( 无向图双连通分量)

题目链接

题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点。任意两个连接点之间最多只有一条隧道。任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案。

分析:本题相当于在一张无向图上选择尽量少的点涂黑(对应太平井),使任意一个点被删除后,每个连通分量都至少还有一个黑点。不同的连通分量最多有一个公共点即割点,将割点涂上是不划算的,因为删除割点后,要保证每个连通分量还要有黑点,所以还要在其他的连通分量中涂黑点,如果不涂割点,还能省一个呢,在一个点连通分量中涂两个黑点也是不划算的, 所以只有当一个点连通分量中含有一个割点,那么就涂 除了 割点 其他的点,因为,如果删除这个割点后,你得保证剩下的有一个黑点。 对于一个连通分量中含有 >= 2个割点,就不用涂了,因为他有两个割点不会全部删除,可以通向其他的连通分量的 太平井,

  1 #include <iostream>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <cstdio>
  5 #include <vector>
  6 #include <stack>
  7 using namespace std;
  8 typedef long long LL;
  9 const int Max = 50005;
 10 struct Edge
 11 {
 12     int u, v;
 13 };
 14 vector<int> G[Max], bcc[Max];
 15 int pre[Max], bccno[Max], iscut[Max];
 16 int dfs_clock, bcc_cnt;
 17 stack<Edge> S;
 18 int dfs(int u, int fa)
 19 {
 20     int lowu = pre[u] = ++dfs_clock;
 21     int Size = G[u].size();
 22     int child = 0;
 23     for (int i = 0; i < Size; i++)
 24     {
 25         int v = G[u][i];
 26         Edge e;
 27         e.u = u;
 28         e.v = v;
 29         if (!pre[v])
 30         {
 31             S.push(e);
 32             child++;
 33             int lowv = dfs(v, u);
 34             lowu = min(lowu, lowv);
 35             if (lowv >= pre[u])
 36             {
 37                 iscut[u] = true;
 38                 bcc_cnt++;
 39                 bcc[bcc_cnt].clear();
 40                 for (; ;)
 41                 {
 42                     Edge x = S.top();
 43                     S.pop();
 44                     if (bccno[x.u] != bcc_cnt)
 45                     {
 46                         bccno[x.u] = bcc_cnt;
 47                         bcc[bcc_cnt].push_back(x.u);
 48                     }
 49                     if (bccno[x.v] != bcc_cnt)
 50                     {
 51                         bccno[x.v] = bcc_cnt;
 52                         bcc[bcc_cnt].push_back(x.v);
 53                     }
 54                     if (x.u == u && x.v == v)
 55                         break;
 56                 }
 57             }
 58         }
 59         else if (pre[v] < pre[u] && v != fa)
 60             lowu = min(lowu, pre[v]);
 61     }
 62     if (child == 1 && fa < 0)
 63         iscut[u] = 0;
 64     return lowu;
 65 }
 66 void find_bcc(int n)
 67 {
 68     if (!S.empty())
 69         S.pop();
 70     memset(pre, 0, sizeof(pre));
 71     memset(bccno, 0, sizeof(bccno));
 72     memset(iscut, 0, sizeof(iscut));
 73     dfs_clock = bcc_cnt = 0;
 74     for (int i = 1; i <= n; i++)
 75     {
 76         if (!pre[i])
 77             dfs(i, -1);
 78     }
 79 }
 80 int main()
 81 {
 82     int test = 0, n;
 83     while (scanf("%d", &n) != EOF && n)
 84     {
 85         int u, v, temp = -1;
 86         for (int i = 1; i < Max; i++)
 87             G[i].clear();  //清空
 88         for (int i = 1; i <= n; i++)
 89         {
 90             scanf("%d%d", &u, &v);
 91             G[u].push_back(v);
 92             G[v].push_back(u);
 93             temp = max(temp, max(u, v));  // 找到最大的点
 94         }
 95         find_bcc(temp);  // 找连通分量
 96         LL ans1 = 0, ans2 = 1;
 97         for (int i = 1; i <= bcc_cnt; i++)
 98         {
 99             int cut_cnt = 0;
100             int Size = bcc[i].size();
101             for (int j = 0; j < Size; j++)
102             {
103                 if (iscut[ bcc[i][j] ])
104                     cut_cnt++;
105             }
106             if (cut_cnt == 1)
107             {
108                 ans1++;
109                 ans2 *= (LL)(Size - 1);
110             }
111         }
112         if (bcc_cnt == 1)
113         {
114             ans1 = 2;
115             ans2 = (LL) bcc[1].size() * (LL) (bcc[1].size() - 1) / 2;
116         }
117         printf("Case %d: %lld %lld\n", ++test, ans1, ans2);
118     }
119     return 0;
120 }

时间: 2024-11-03 20:58:54

UVA5135 Mining Your Own Business ( 无向图双连通分量)的相关文章

UVA 1108 - Mining Your Own Business(双连通分量)

UVA 1108 - Mining Your Own Business 题目链接 题意:给定一个连通图,设置一个些安全点,使得其他任意一些节点崩塌后,其他点都能到一个安全点,问安全点最小数量和情况数 思路: #include <cstdio> #include <cstring> #include <vector> #include <stack> #include <map> using namespace std; const int N =

无向图双连通分量 模板

//点-双连通分量模板. #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<stack> using namespace std; struct Edge { int u,v; };//u,v是边的两个端点 const int maxn=100005; int n,m; int pre[maxn],iscut[maxn],bccno[ma

poj 3177 &amp; 3352 【无向图双连通分量Tarjan】

题目:poj 3177 & 3352 题意:大概意思就是给你一个无向图,让你添加最少的边,让所有点都双连通. 分析:双连通的定义就是任意两个点至少有两条路可达. 其实做法跟添加最少边强连通一样,先对图中已经双连通的缩点,然后重新编号. 这就是著名的Tanjan算法. 通过搜索的思想对所有存在环的边遍相同的号 如果要让所有的点双连通,那么对于缩点后的图中如果度数为 1 的话,这些边肯定要连接到其他的点才能双连通,而题目要求添加最少,所以连接到其他度数也为 1 的点是最优的,那么答案就是(odd+1

Mining Your Own Business(点双联通)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19845 大意:有一座地下矿, 有n条隧道相连, 任意两个连接点之间只有一条隧道相连接. 为了降低矿工的危险, 现在决定在连接点处建一些逃生装置, 使得不管哪个连接点倒塌, 不在此连接点的所有矿工都能逃生. 问安装最少的逃生装置, 及其安装的方案. 分析题可知, 这是求点双联通分量的, 我们只要把只有一个割点的点双联通分量安装一个逃生装置即可. 安装的方案数就是点双

hdu3844 Mining Your Own Business,无向图的双连通分量

点击打开链接 无向图的双连通分量 #include<cstdio> #include<stack> #include<vector> #include<map> #include<algorithm> #include<cstring> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long lo

hdu 3844 Mining Your Own Business (点双连通分量)

Mining Your Own Business Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1392    Accepted Submission(s): 219 Problem Description John Digger is the owner of a large illudium phosdex mine. The m

UVALive 5135 Mining Your Own Business 双连通分量 2011final

题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点.任意两个连接点之间最多只有一条隧道.任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案. 思路:其实本题就相当于在一张无向图中,涂尽量少的黑点,使得任意删除哪个点,每个连通分量至少有一个黑点.因为不同的连通分量最多只有一个公共点,那一定是割点.可以发现,涂黑割点是不划算的,而且在 一个点-双连通分量中涂黑两个黑点也是不划算的.所以只有当点-双连通分量只有一个割点时

UVALive - 5135 Mining Your Own Business(双连通分量)

题目大意:有N个矿井 ,由一些隧道连接起来,现在要修建尽量少的安全通道,使得无论哪里发生事故,所有人均能逃出,求建的最少的安全通道数量和方案数 解题思路:建安全通道的话,肯定不能建在割顶,因为割顶如果崩塌了,割顶所连接的双连通分量内的点就跑不掉了,还得在双连通分量里面再建点(上述为双连通分量内部只有一个割顶的情况),这样不划算,还不如直接在里面建点 如果一个双连通分量的内部割顶有多个的话,那么在这个双连通分量里面就可以不用建安全通道了,因为一个割顶崩塌了,还有其他点可以连向外面,所以,只考虑内部

图论--无向图点双连通分量模板

对于一个无向图,如果一个点集,它内部的任意一个点对之间,至少有两条点完全不重复的路径,那么这个点集就是原图的一个点双连通分量,而点双联通分量之间是由割点隔开,割点就是如果删去这个点,原图的连通块数会增加,那么这个点就是割点. 通过tarjan算法,我们可以用一次 dfs 标记出所有的割点以及所有双连通分量. 注释版: 1 #include<stdio.h> 2 #include<string.h> 3 #include<stack> 4 #include<algo