【HDU3849】求无向图的割边
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3849
题目大意:给你一个关系网,问你那两个人是关键关系,即在整个关系网中起到链接作用,不可失去,这样对应到无向图中不就是要你求哪些边不在强连通分量中吗,即不在任何环中的边。
解题思路: 利用tarjan算法的变形,以前用tarjan求的是有向图的强连通分量,这个是无向图,所以要进行相应的变形。
1、 首先,要求割边则对应的图必须是连通图,如果不是连通图那么割边就是0.
2、开始WA了几次,因为我开始这么想:一条边连接的两个顶点只要在不同的连通分量中(low[]值不同),那么这条边就是割边,好像想想有道理唉?这样是错的,因为当出现两个强连通分量共边(即理解成两个环共边时),两个顶点的low[]值可能不同。
割边的必要条件:low[u]!=low[v]
割边的充分必要条件:low[u]>dfn[v] || low[v]>dfn[u]。
View Code
1 #include <iostream> 2 #include <cstdio> 3 #include <map> 4 #include <algorithm> 5 #include <cstring> 6 using namespace std; 7 8 const int maxn=222222; 9 int dfn[maxn], low[maxn], head[maxn]; 10 int reach[maxn], next[maxn]; 11 int top, Index, edge; 12 13 struct node 14 { 15 char s[20]; 16 friend bool operator <(const node &A, const node &B) 17 { 18 return strcmp(A.s,B.s)<0; 19 } 20 }; 21 map<node,int>mp; 22 23 struct Node 24 { 25 node x, y; 26 int flag; 27 }f[maxn]; 28 29 void init() 30 { 31 memset(head,-1,sizeof(head)); 32 memset(dfn,0,sizeof(dfn)); 33 edge=0; 34 } 35 36 void addedge(int u, int v) 37 { 38 reach[edge]=v, next[edge]=head[u], head[u]=edge++; 39 } 40 41 void tarjan(int u, int fa) 42 { 43 dfn[u]=low[u]=++Index; 44 for(int i=head[u]; i>=0; i=next[i]) 45 { 46 int v=reach[i]; 47 if(v==fa) continue; 48 if(!dfn[v]) tarjan(v,u), low[u]=min(low[u],low[v]); 49 else low[u]=min(low[u],dfn[v]); 50 } 51 } 52 53 int main() 54 { 55 int n, m, T; 56 cin >> T; 57 while(T--) 58 { 59 int id=0; 60 mp.clear(); 61 scanf("%d%d",&n,&m); 62 init(); 63 for(int i=0; i<m; i++) 64 { 65 f[i].flag=0; 66 scanf("%s%s",&f[i].x.s,&f[i].y.s); 67 if(mp.find(f[i].x)==mp.end()) mp[f[i].x]=++id; 68 if(mp.find(f[i].y)==mp.end()) mp[f[i].y]=++id; 69 int u=mp[f[i].x], v=mp[f[i].y]; 70 addedge(u,v), addedge(v,u); 71 } 72 tarjan(1,-1); 73 bool ok=true; 74 for(int i=1; i<=n; i++) 75 if(!dfn[i]){ ok=false; break; } 76 if(!ok) puts("0"); 77 else 78 { 79 int ans=0; 80 for(int i=0; i<m; i++) 81 { 82 int u=mp[f[i].x], v=mp[f[i].y]; 83 if(low[u]>dfn[v]||low[v]>dfn[u]) ans++, f[i].flag=1; ///!!! 84 } 85 printf("%d\n",ans); 86 for(int i=0; i<m; i++) 87 if(f[i].flag) printf("%s %s\n",f[i].x.s,f[i].y.s); 88 } 89 } 90 return 0; 91 }