这题是比较模板的找点双联通并记录的题目。

  题意大概是:一个公园有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\n",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 }