【UVA10972】RevolC FaeLoN (求边双联通分量)
2016-03-23 13:54
363 查看
题意:
给你一个无向图,要求把所有无向边改成有向边,并且添加最少的有向边,使得新的有向图强联通。
分析:
这题的解法还是很好想的。先用边双联通分量缩点,然后找新图中入度为0和为1的点,入度为0则ans+2,为1则ans+1,最后输出(ans+1)/2。
注意,如果原图本来就强联通,答案为0不是1。
在这里主要说说打边双联通的注意事项。(一开始觉得是跟点双连通差不多的,调试的时候才发现很容易疏忽导致BUG很多啊)
1、如果有重边,则那条就不是割边了,我们很容易向上重走树枝边的反向边导致程序认为这是返祖边。在点双连通中判断一下是不是父亲即可,但边双联通不行。(因为重边对点双连通无影响,但对边双联通有影响)所以要做一个标记,走树枝边的时候把反向边也标记一下。
2、stack中的剩余元素最后要记得pop出来。
3、图不一定联通,要for一遍再dfs。
4、发现(x,y)为割边的时候,(dfn[x]<dfn[y]),边双联通分量是算到y而不是x。(跟点双连通有一点不一样)
代码如下:
[uva10972]
2016-03-23 13:54:57
给你一个无向图,要求把所有无向边改成有向边,并且添加最少的有向边,使得新的有向图强联通。
分析:
这题的解法还是很好想的。先用边双联通分量缩点,然后找新图中入度为0和为1的点,入度为0则ans+2,为1则ans+1,最后输出(ans+1)/2。
注意,如果原图本来就强联通,答案为0不是1。
在这里主要说说打边双联通的注意事项。(一开始觉得是跟点双连通差不多的,调试的时候才发现很容易疏忽导致BUG很多啊)
1、如果有重边,则那条就不是割边了,我们很容易向上重走树枝边的反向边导致程序认为这是返祖边。在点双连通中判断一下是不是父亲即可,但边双联通不行。(因为重边对点双连通无影响,但对边双联通有影响)所以要做一个标记,走树枝边的时候把反向边也标记一下。
2、stack中的剩余元素最后要记得pop出来。
3、图不一定联通,要for一遍再dfs。
4、发现(x,y)为割边的时候,(dfn[x]<dfn[y]),边双联通分量是算到y而不是x。(跟点双连通有一点不一样)
代码如下:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<stack> using namespace std; #define Maxn 1010 struct node { int x,y,next; bool vis; }t[2*Maxn*Maxn];int len; int first[Maxn],n,m; int dfn[Maxn],low[Maxn],cnt; int cc[Maxn],cl,sum[Maxn]; stack<int > s; void ins(int x,int y) { t[++len].x=x;t[len].y=y;t[len].vis=0; t[len].next=first[x];first[x]=len; } int mymin(int x,int y) {return x<y?x:y;} void ffind(int x) { dfn[x]=low[x]=++cnt; s.push(x); for(int i=first[x];i;i=t[i].next) if(!t[i].vis) { int y=t[i].y; t[i].vis=1;t[i+(i%2==1?1:-1)].vis=1; if(!dfn[y]) { ffind(y); low[x]=mymin(low[x],low[y]); if(low[y]>dfn[x]) { cl++; while(!s.empty()) { int z=s.top(); s.pop(); cc[z]=cl; if(z==y) break; } } } else low[x]=mymin(low[x],dfn[y]); } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { len=0;cnt=0;cl=0; memset(first,0,sizeof(first)); memset(dfn,0,sizeof(dfn)); memset(cc,0,sizeof(cc)); memset(sum,0,sizeof(sum)); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } if(!s.empty()) s.pop(); for(int i=1;i<=n;i++)if(!dfn[i]) { ffind(i); if(!s.empty()) { cl++; while(!s.empty()) { cc[s.top()]=cl; s.pop(); } } } if(cl==1) {printf("0\n");continue;} int ans=0; for(int i=1;i<=len;i++) { if(cc[t[i].x]==cc[t[i].y]) continue; sum[cc[t[i].x]]++; } for(int i=1;i<=cl;i++) if(sum[i]==1) ans++; else if(sum[i]==0) ans+=2; printf("%d\n",(ans+1)/2); } return 0; }
[uva10972]
2016-03-23 13:54:57
相关文章推荐
- Unity3d 5烘焙相关
- 每天一点Linux--图形界面回到命令行
- 【C++】C++常见面试题汇总,持续更新中...
- bash实现两个文件的并交减集合操作
- HRBUST 2010 二等队形 最长递减子序列
- Oracle数据库用户的密码保存位置说明
- Java中的final关键字-----(java复习)
- Web报表工具FineReport的JS API开发(二)
- UESTC - 1271 Search gold (DP)
- Jquery+ajax+JAVA(servlet)实现下拉菜单异步取值
- 10 个 Redis 建议/技巧
- Android之ContentProvider总结
- 框架中web.xml中配置文件解析
- JavaScript中的setInterval用法
- //5.4 编写一个程序,求以下矩形两条对角线上的元素之和: //1 3 6 //7 9 11 //14 15 17
- 八皇后问题
- foregroundRender_seceneRender
- JVM性能监测
- IOS开发之下拉列表控件开发
- HashMap和Hashtable的区别