【HDU4612】 双连通分量求桥
2013-07-28 15:05
183 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612
题目大意:给你一个无向图,问你加一条边后最少还剩下多少多少割边。
解题思路:好水的一道模板题。先缩点变成一颗树,再求树的最长直径,直径两端连一条边就是最优解了。
但是....我WA了一个下午.....没有处理重边。
重边的正确处理方法:只标记已经走过的正反边,而不限制已走过的点。换句话说就是可以经过重边再次走向父亲节点,而不能经过走过边的反向边返回父亲节点。
View Code
题目大意:给你一个无向图,问你加一条边后最少还剩下多少多少割边。
解题思路:好水的一道模板题。先缩点变成一颗树,再求树的最长直径,直径两端连一条边就是最优解了。
但是....我WA了一个下午.....没有处理重边。
重边的正确处理方法:只标记已经走过的正反边,而不限制已走过的点。换句话说就是可以经过重边再次走向父亲节点,而不能经过走过边的反向边返回父亲节点。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <cstdio> #include <queue> #include <algorithm> #include <cstring> using namespace std; const int maxn=222222; const int maxm=2222222; int dfn[maxn], low[maxn], head[maxn], stack[maxn], instack[maxn], belong[maxn]; int reach[maxm], next[maxm], sign[maxm]; int visit[maxn]; int top, Index, scnt, edge, pos, bridgenum; int n, m; pair<int,int>num[maxm]; struct node { int u; int dis; int fa; }; queue<node>q; void init() { memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(instack,0,sizeof(instack)); Index=top=edge=scnt=bridgenum=0; } void addedge(int u, int v) { sign[edge]=0, reach[edge]=v, next[edge]=head[u], head[u]=edge++; sign[edge]=0, reach[edge]=u, next[edge]=head[v], head[v]=edge++; } void tarjan(int u) { stack[++top]=u; dfn[u]=low[u]=++Index; instack[u]=1; for(int i=head[u]; i>=0; i=next[i]) { if(sign[i]) continue; sign[i]=1, sign[i^1]=1; ///处理重边,只标记边,而不限制点 int v=reach[i]; if(!dfn[v]) { tarjan(v), low[u]=min(low[u],low[v]); if(dfn[u]<low[v]) bridgenum++; ///求桥的数量 } else if(instack[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { int v; scnt++; ///双连通分量的数量 do { v=stack[top--]; instack[v]=0; belong[v]=scnt; } while(u!=v); } } int bfs(int st) { int maxx=0; while(!q.empty()) q.pop(); memset(visit,0,sizeof(visit)); node s, p; s.u=st, s.dis=0, s.fa=-1; q.push(s); visit[s.u]=1; while(!q.empty()) { p=q.front(); q.pop(); for(int i=head[p.u]; i>=0; i=next[i]) { int v=reach[i]; if(v==p.fa) continue; s.u=v, s.dis=p.dis+1, s.fa=p.u; if(!visit[s.u]) { visit[s.u]=1, q.push(s); if(s.dis>maxx) { maxx=s.dis; pos=s.u; } } } } return maxx; } void Solve() { memset(head,-1,sizeof(head)); edge=0; for(int i=1; i<=m; i++) { int u=num[i].first, v=num[i].second; int x=belong[u], y=belong[v]; if(x!=y) addedge(x,y); } bfs(1); int ans=bfs(pos); cout << bridgenum-ans <<endl; } int main() { while(cin >> n >> m, n+m) { init(); for(int i=1; i<=m; i++) { int u, v; scanf("%d%d",&u,&v); num[i].first=u, num[i].second=v; addedge(u,v); } for(int i=1; i<=n; i++) if(!dfn[i]) tarjan(i); Solve(); } return 0; } /* 10 11 1 2 2 3 3 4 2 4 3 6 5 10 5 7 7 8 8 9 7 9 3 5 */
View Code
相关文章推荐
- hdu4612-Warm up(边的双连通分量)
- poj 3352 (构造双连通分量)
- 【tarjan求双连通分量+染色判二分图】POJ 2942
- poj 3177 缩点,双连通分量
- POJ-3177 Redundant Paths 双连通分量
- HDU 4612 Warm up(双连通分量)#by zh
- hdu4612 Warm up 树形dp 桥 强连通分量
- HDU 3749 Financial Crisis 点双连通分量
- POJ 2942 Knights of the Round Table 点的双连通分量 + 奇圈
- poj 3352(边双连通分量)
- Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告)
- 连通分量模板:tarjan: 求割点 && 桥 && 缩点 && 强连通分量 && 双连通分量 && LCA(最近公共祖先)
- ASC(22)C(最短路+双连通分量找桥或拓扑排序)
- poj Knights of the Round Table 点双连通分量
- 双连通分量求解===
- poj 3352 双连通分量
- hiho一下 第五十三周(无向图的双连通分量)
- UVALive - 3523 Knights of the Round Table(无向图的双连通分量)
- 边的双连通分量问题
- 无向图求割顶双连通分量