UVALive 5135 Mining Your Own Business(BCC、割顶)
来源:互联网 发布:icloud中的备份恢复mac 编辑:程序博客网 时间:2024/05/29 08:55
题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3136
题目大意:有n条隧道和一些连接点,要在一些连接点修建逃生装置,使得不管哪个点发生坍塌,其他点的人都可以从逃生。让你求出应该安装的最少逃生装置的数量和方案数。
解题思路:经过了上一题,这一题其实还比较好想。一张图,点会坍塌,然后逃生,很容易想到割顶。然后发现用割顶装逃生装置是不合算的,不是割顶的才好。对于一个双连通分量,只有一个割顶的需要在任何一个非割顶的点装就行了。割顶数>=2个的,不需要装,反正有路能跑到其他地方去。然后还有一点容易忽略,我也开始没想到:如果整张图没有割顶,那么就是任选两个点装逃生装置,方案数是 V*(V-1)/2,V 为 点数。
一开始交错题号了,一直WA,还检查了老半天。。 = =
代码如下:
#include<cstdio>#include<cstring>#include<stack>#include<vector>#include<algorithm>using namespace std;typedef long long lld;const int MAXN = 50005<<1;struct Edge{ int u,v;};vector <int> G[MAXN],bcc[MAXN];stack <Edge> S;int pre[MAXN],is_cut[MAXN],bccno[MAXN];int bcc_cnt,dfs_clock;int dfs(int u,int fa){ int low_u = pre[u] = ++dfs_clock; int child = 0; for(int i = 0;i < G[u].size();i++) { int v = G[u][i]; Edge e = (Edge){u,v}; if(!pre[v]) { child++; S.push(e); int low_v = dfs(v,u); low_u = min(low_u,low_v); if(low_v >= pre[u]) { is_cut[u] = 1; bcc_cnt++; bcc[bcc_cnt].clear(); for(;;) { Edge x = S.top(); S.pop(); if(bccno[x.u] != bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u] = bcc_cnt; } if(bccno[x.v] != bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v] = bcc_cnt; } if(x.u == u && x.v == v) break; } } } else if(pre[v] < pre[u] && v != fa) { S.push(e); low_u = min(low_u,pre[v]); } } if(child == 1 && fa == -1) is_cut[u] = 0; return low_u;}void find_bcc(int n){ memset(pre,0,sizeof(pre)); memset(is_cut,0,sizeof(is_cut)); memset(bccno,0,sizeof(bccno)); dfs_clock = bcc_cnt = 0; for(int i = 0;i < n;i++) if(!pre[i]) dfs(i,-1);}int main(){ int cas = 0; int n; while(~scanf("%d",&n) && n) { for(int i = 0;i < 2*n;i++) G[i].clear(); int max_id = 0; for(int i = 0;i < n;i++) { int a,b; scanf("%d%d",&a,&b); max_id = max(max_id,a); max_id = max(max_id,b); a--;b--; G[a].push_back(b); G[b].push_back(a); } find_bcc(max_id); //printf("bcc_cnt = %d\n",bcc_cnt); int ans_num = 0; lld ans_count = 1; if(bcc_cnt == 1) { ans_num = 2; ans_count = (lld)bcc[1].size()*(bcc[1].size()-1)/2; } else { for(int i = 1;i <= bcc_cnt;i++) { int cc = 0; for(int j = 0;j < bcc[i].size();j++) if(is_cut[bcc[i][j]] == 1) cc++; if(cc == 1) { ans_num++; ans_count *= bcc[i].size()-1; } } } printf("Case %d: %d %lld\n",++cas,ans_num,ans_count); } return 0;}
另外一种,也就是只做找割顶,不做BCC,其实差不多,基本思路一样。就是先找出所有割顶,然后对对不是割顶的点进行dfs,找遍这个连通分量的所有点,过程中不经过割顶,但记录个数,如果数目是1,就更新答案(更新方法和上面一样)。同样,也要特判割顶为0的情况。
代码如下:
#include<cstdio>#include<cstring>#include<stack>#include<vector>#include<algorithm>using namespace std;typedef long long lld;const int MAXN = 50005<<1;vector <int> G[MAXN];int pre[MAXN],is_cut[MAXN];int dfs_clock;int dfs(int u,int fa){ int low_u = pre[u] = ++dfs_clock; int child = 0; for(int i = 0;i < G[u].size();i++) { int v = G[u][i]; if(!pre[v]) { child++; int low_v = dfs(v,u); low_u = min(low_u,low_v); if(low_v >= pre[u]) { is_cut[u] = 1; } } else if(pre[v] < pre[u] && v != fa) { low_u = min(low_u,pre[v]); } } if(child == 1 && fa == -1) is_cut[u] = 0; return low_u;}void find_bcc(int n){ memset(pre,0,sizeof(pre)); memset(is_cut,0,sizeof(is_cut)); dfs_clock = 0; for(int i = 0;i < n;i++) if(!pre[i]) dfs(i,-1);}int vis[MAXN];vector <int> cut;void dfs1(int u,int& cc,int& tot){ vis[u] = 1; tot++; for(int i = 0;i < G[u].size();i++) { int v = G[u][i]; if(!vis[v]) { if(is_cut[v]) { vis[v] = 1; cc++; cut.push_back(v); continue; } dfs1(v,cc,tot); } }}int main(){ int cas = 0; int n; while(~scanf("%d",&n) && n) { for(int i = 0;i < 2*n;i++) G[i].clear(); int max_id = 0; for(int i = 0;i < n;i++) { int a,b; scanf("%d%d",&a,&b); max_id = max(max_id,a); max_id = max(max_id,b); a--;b--; G[a].push_back(b); G[b].push_back(a); } find_bcc(max_id); int ans_num = 0; lld ans_count = 1; int cc = 0; for(int i = 0;i < max_id;i++) if(is_cut[i]) cc++; if(cc == 0) { ans_num = 2; ans_count = (lld)max_id*(max_id-1)/2; } else { memset(vis,0,sizeof(vis)); for(int i = 0;i < max_id;i++) if(!vis[i] && !is_cut[i]) { int cc = 0; int tot = 0; cut.clear(); dfs1(i,cc,tot); if(cc == 1) { ans_num++; ans_count *= tot; } for(int j = 0;j < cut.size();j++) vis[cut[j]] = 0; } } printf("Case %d: %d %lld\n",++cas,ans_num,ans_count); } return 0;}/*61 21 32 33 43 54 5*/
0 0
- UVALive 5135 Mining Your Own Business(BCC、割顶)
- 【UVALive】5135 Mining Your Own Business 点双连通+割顶
- UVALive - 5135 Mining Your Own Business
- UVALive - 5135 Mining Your Own Business
- uvalive 5135 Mining Your Own Business(双连通分量)
- LA 5135 Mining Your Own Business (求割点与BCC)
- UVALive5135 - Mining Your Own Business(BCC)
- UVALive 5135 HDU 3844 Mining Your Own Business
- UVALive 5135 - Mining Your Own Business(点双连通)
- UVALive - 5135 Mining Your Own Business(双连通分量)
- UVALive 5135 Mining Your Own Business(点双连通分量)
- Mining Your Own Business
- LA 5135 Mining Your Own Business
- Mining Your Own Business LA 5135
- UVAlive 5135 Mining Your Own Business [点双连通分量] [求割顶]
- LA5135 Mining Your Own Business
- La5135 Mining your own Business
- UVA 1108 - Mining Your Own Business(双连通分量)
- CIFS
- XML第一讲:XML基本讲解
- [Oracle SQL] 使用rollup分组统计按统计结果分组排序显示的问题
- iOS学习之2-使用ASIHttpRequest调用WebService
- hdu 1231 最长子序类
- UVALive 5135 Mining Your Own Business(BCC、割顶)
- 大数据量数据库优化
- JAVA中this用法小结
- Linux下OpenCV2.4.x的安装与配置
- Linux内核链表学习笔记
- java解析xml的几种方式
- 多人报数问题
- poj2039
- 个人感悟