这题是比较模板的找点双联通并记录的题目。
题意大概是:一个公园有n个景点,1.所有游客都是绕环旅游的,找出所有不在环内的路的条数;2.如果两个环中有重复的边,那么这些边是冲突的,问冲突的边的总数。
分析:1.即桥的条数;2.找出点双联通分量,在他们内部找重复的边,或者换句话说,找出所有点双联通分量,边数大于点数的,这些边都是冲突的。
那么,什么是点双联通分量呢,就是任意两点都有两条或以上的路径,这些路径的点除了这两点以外,都不相同,或者说,内部无割点,像数字8的形状就不是,8是边双联通;或者再换句话说,任意两边都在一个简单环内。
而边双联通图呢,是任意一边都在一个简单环内。或者说,所有边都不是桥。
搞清楚这两点就可以了。然后代码都是模板的问题,代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <vector> 5 #include <stack> 6 #include <set> 7 using namespace std; 8 typedef pair<int,int> pii; 9 10 int n,m; 11 vector<int> G[10000+5]; 12 int dfn[10000+5],low[10000+5]; 13 int dfs_clock,cnt_qiao,cnt_scc; 14 vector<pii> block[10000+5]; 15 int vis[10000+5]; 16 stack<pii> S; 17 18 void init() 19 { 20 for(int i=0;i<n;i++) G[i].clear(); 21 memset(dfn,0,sizeof(dfn)); 22 dfs_clock=0; 23 cnt_qiao=0; 24 cnt_scc=0; 25 for(int i=0;i<n;i++) block[i].clear(); 26 } 27 28 void dfs(int u,int fa) 29 { 30 dfn[u]=low[u]=++dfs_clock; 31 for(int i=0;i<G[u].size();i++) 32 { 33 int v = G[u][i]; 34 if(v==fa) continue; 35 //S.push(pii(u,v)); 36 //不能在这里push边,不然会出现重边 37 38 if(!dfn[v]) //这是从父到子的访问顺序,只有这个顺序才能判断是不是割点或者桥 39 { 40 S.push(pii(u,v)); 41 dfs(v,u); 42 low[u]=min(low[u],low[v]); 43 44 if(dfn[u]<=low[v]) //这一点是准割点(在根处不成立) 45 { 46 for(;;) 47 { 48 pii t = S.top();S.pop(); 49 block[cnt_scc].push_back(t); 50 if(t.first==u && t.second==v) break; 51 } 52 cnt_scc++; 53 } 54 if(dfn[u]<low[v]) cnt_qiao++; 55 } 56 else if(dfn[v]<dfn[u]) //这是子到父的访问顺序,即反向边 57 { 58 S.push(pii(u,v)); 59 low[u]=min(low[u],dfn[v]); 60 } 61 } 62 } 63 64 void solve() 65 { 66 for(int i=0;i<n;i++) if(!dfn[i]) dfs(i,-1); 67 68 int cnt=0; 69 70 for(int i=0;i<cnt_scc;i++) 71 { 72 memset(vis,0,sizeof(vis)); 73 int cnt_edge = block[i].size(); 74 int cnt_point=0; 75 for(int j=0;j<block[i].size();j++) 76 { 77 pii t = block[i][j]; 78 int u = t.first,v = t.second; 79 if(!vis[u]) vis[u]=1,cnt_point++; 80 if(!vis[v]) vis[v]=1,cnt_point++; 81 } 82 83 if(cnt_point<cnt_edge) 84 { 85 cnt+=cnt_edge; 86 } 87 } 88 89 printf("%d %d ",cnt_qiao,cnt); 90 } 91 92 int main() 93 { 94 while(scanf("%d%d",&n,&m)==2) 95 { 96 if(n==0 && m==0) break; 97 init(); 98 99 for(int i=1;i<=m;i++) 100 { 101 int u,v; 102 scanf("%d%d",&u,&v); 103 G[u].push_back(v); 104 G[v].push_back(u); 105 } 106 107 solve(); 108 } 109 return 0; 110 }