hdu 4612 Warm up (边BCC缩点、带重边)
2015-06-28 12:29
435 查看
题目大意:有重边的无向图,问添加一条边最多能够减少多少个桥。
求出边-连通分量,缩点后得到一棵树。在该树中,所有的边都是桥,找LCA最远的两个叶子节点(就是树的直径),其所含的桥个数最多。因此连接该两个叶子节点可使得桥的个数减少最多。这是基本的算法思想。
然后的问题是如何处理重边?
”一般的简单无向图,tarjan求桥的dfs有两个参数x和fa,其中参数fa就是用于判定某边(x,t)是不是刚刚走过来的边.通常是用fa标记父节点。
在有重边的情形下,这样判就不太方便了。因为标记父节点之后就可能无法访问从fa出发的另一条重边了。
于是我们修改这个判定条件,把参数fa改为刚刚走过来的这条边的编号.
这就没问题了.至于具体的实现,由于一条无向边拆成两条有向边存下来的时候,编号是连续的,因此像类似4,5这样的两条边,可以通过判断4/2==5/2来判定是否是由同一条无向边拆出来的“
再一个就是如何求树的直径?相关证明
最后还有个问题:数据量很大。很容易爆栈。得加上这句
#pragma comment(linker,"/STACK:1024000000,1024000000")
然后用C++提交。
#pragma comment(linker,"/STACK:1024000000,1024000000")
求出边-连通分量,缩点后得到一棵树。在该树中,所有的边都是桥,找LCA最远的两个叶子节点(就是树的直径),其所含的桥个数最多。因此连接该两个叶子节点可使得桥的个数减少最多。这是基本的算法思想。
然后的问题是如何处理重边?
”一般的简单无向图,tarjan求桥的dfs有两个参数x和fa,其中参数fa就是用于判定某边(x,t)是不是刚刚走过来的边.通常是用fa标记父节点。
在有重边的情形下,这样判就不太方便了。因为标记父节点之后就可能无法访问从fa出发的另一条重边了。
于是我们修改这个判定条件,把参数fa改为刚刚走过来的这条边的编号.
这就没问题了.至于具体的实现,由于一条无向边拆成两条有向边存下来的时候,编号是连续的,因此像类似4,5这样的两条边,可以通过判断4/2==5/2来判定是否是由同一条无向边拆出来的“
再一个就是如何求树的直径?相关证明
最后还有个问题:数据量很大。很容易爆栈。得加上这句
#pragma comment(linker,"/STACK:1024000000,1024000000")
然后用C++提交。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<stack> #include<queue> #pragma comment(linker,"/STACK:1024000000,1024000000") using namespace std; #define N 200005 struct Edge{ int v,next; }edge[2000010]; int pre ,S ,top,low ,head ,cnt,dfs_clock,bcc_cnt,bccno ,bridge; inline void add(int u,int v){ edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; } void dfs(int u,int fa){ pre[u]=low[u]=++dfs_clock; S[top++]=u; for(int i=head[u];~i;i=edge[i].next){ if(i==(fa^1)) continue; int v=edge[i].v; if(!pre[v]){ dfs(v,i); low[u]=min(low[u],low[v]); } else if(!bccno[v]) low[u]=min(low[u],pre[v]); } if(low[u]==pre[u]){ ++bcc_cnt; for(;;){ int x=S[--top]; bccno[x]=bcc_cnt; if(x==u) break; } } } inline void find_bcc(int n){ memset(pre,0,sizeof(pre)); memset(bccno,0,sizeof(bccno)); dfs_clock=bcc_cnt=bridge=top=0; for(int i=0;i<n;++i) if(!pre[i]) dfs(i,-1); } vector<int>G ; int d ; bool vis ; queue<int>q; int bfs(int s,int &t){ memset(d,0,sizeof(d)); memset(vis,0,sizeof(vis)); t=s; int ans=0; q.push(s); vis[s]=1; while(!q.empty()){ int u=q.front(); q.pop(); for(int i=0;i<G[u].size();++i){ int v=G[u][i]; if(!vis[v]){ vis[v]=1; d[v]=d[u]+1; if(d[v]>ans){ ans=d[v]; t=v; } q.push(v); } } } return ans; } int main() { int i,j,n,m,x,y; while(~scanf("%d%d",&n,&m)&&(n+m)){ memset(head,-1,sizeof(head)); cnt=0; for(i=0;i<m;++i){ scanf("%d%d",&x,&y); add(--x,--y); add(y,x); } find_bcc(n); for(i=1;i<=bcc_cnt;++i) G[i].clear(); for(i=0;i<n;++i) for(j=head[i];~j;j=edge[j].next){ int v=edge[j].v; if(bccno[v]!=bccno[i]) G[bccno[i]].push_back(bccno[v]); } int p,ans=bfs(1,p); ans=max(ans,bfs(p,p)); printf("%d\n",bcc_cnt-1-ans); } return 0; }
#pragma comment(linker,"/STACK:1024000000,1024000000")
相关文章推荐
- struts2 标签使用 iterator 嵌套使用设置默认值 s:radio 设置默认值
- 大话设计模式C++版——建造者模式
- ZooKeeper 笔记(4) 实战应用之【消除单点故障】
- 大话设计模式C++版——建造者模式
- python中getaddrinfo()基本用法实例分析
- VirtualBox下快速创建新的虚拟机(一)——复制vdi文件
- EBGP与IBGP的区别
- <s:select 标签的设置宽度的问题
- Android Socket 通信实例...【Pnoker】
- 读《嵌入式系统开发之道:菜鸟成长日志》00
- [转]Hive:简单查询不启用Mapreduce job而启用Fetch task
- android菜鸟学习笔记8----Activity(一)
- OJ友元类-计算两点间距离
- codeforce 310 div2 D题 Case of Fugitive
- 用代码实现图像的去噪
- 手机输入框抖动效果 和 震动效果
- 【麦可网】Cocos2d-X跨平台游戏开发学习笔记---第二十课:Cocos2D-X场景切换1-3
- 面试题整理:C#(二)
- Select …forupdate语句是我们经常使用手工加锁语句。
- 聊天服务器-解密陌生人(10)位置管理和获取周围一公里陌生人