HDU3394 点双连通分量

Railway

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3655    Accepted Submission(s): 1219


Problem Description
There are some locations in a park, and some of them are connected by roads. The park manger needs to build some railways along the roads, and he would like to arrange tourist routes to each circuit. If a railway belongs to more than one tourist routes, there might be clash on it, and if a railway belongs to none tourist route, it doesn’t need to build.
Now we know the plan, and can you tell us how many railways are no need to build and how many railways where clash might happen.
 
Input
The Input consists of multiple test cases. The first line of each test case contains two integers, n (0 < n <= 10000), m (0 <= m <= 100000), which are the number of locations and the number of the railways. The next m lines, each line contains two integers, u, v (0 <= u, v < n), which means the manger plans to build a railway on the road between u and v.
You can assume that there is no loop and no multiple edges.
The last test case is followed by two zeros on a single line, which means the end of the input.
 
Output
Output the number of railways that are no need to build, and the number of railways where clash might happen. Please follow the format as the sample.
 
Sample Input
8 10 0 1 1 2 2 3 3 0 3 4 4 5 5 6 6 7 7 4 5 7 0 0
 
Sample Output
1 5
 
Author
momodi@whu
 
Source
题意: 一个无向图有n个点和m条边(可能不连通).现在要你找出冲突边和多余边的数目.其中冲突边是同时存在于多个环中的边,而多余边是不在环中的边.
思路:

1.首先多余边就是桥.冲突边只能在点双连通分量中,而什么样的点双连通分量有冲突边呢?

2.对于有n个节点和n条边(或小于n条边)的点双连通分量,这种分量只有一个大环,不存在其他任何环了,所以这种分量中的边都不是冲突边.

3.对于有n个节点和m条边(m>n)的点双连通分量来说,该分量内的所有边都是冲突边.因为边数>点数,所以该分量必有至少两个环,我们随便画个图就可知其中的任意边都至少在两个以上的环上.

综上所述,对于多余边,我们输出桥数.对于冲突边,我们输出边数>点数的点双连通分量的所有边数.

代码:
 1 #include"bits/stdc++.h"
 2 #define rep(i, a, n) for (int i=a;i<n;i++)
 3 #define per(i, a, n) for (int i=n-1;i>=a;i--)
 4 const int N=10010;
 5 const int M=100010;
 6 using namespace std;
 7 int low[N], dfn[N], st[N];
 8 int id, top;
 9 bool vis[N];
10 int a[N], cc;
11 int n, m;
12 int ans1, ans2;
13 struct P{
14     int to,next;
15 }e[M<<1];
16 int head[N],cnt;
17 void add(int u,int v){
18     e[cnt].to = v;
19     e[cnt].next = head[u];
20     head[u] = cnt++;
21 }
22 void dfs(int u,int pre){
23     low[u]=dfn[u]=++id;
24     st[++top]=u;
25     for(int i=head[u];i!=-1;i=e[i].next){
26         int v=e[i].to;
27         if(v==pre) continue;
28         if(!dfn[v]){
29             dfs(v,u);
30             if(low[u]>low[v]) low[u]=low[v];
31             if(low[v]>dfn[u]) ans1++;//
32             if(low[v]>=dfn[u]){
33                 cc=0;
34                 memset(vis,0,sizeof(vis));
35                 int x;
36                 do{
37                     x=st[top--];
38                     a[cc++]=x;//双连通分量中的点存起来
39                     vis[x]=1;//标记
40                 }while(x!=v);
41                 a[cc++]=u;
42                 vis[u]=1;
43                 cal();
44             }
45         }
46         else if(low[u]>dfn[v]) low[u]=dfn[v];
47     }
48 }
49 
50 void cal(){
51     int sum=0;
52     for(int i=0;i<cc;++i){
53         int u=a[i];
54         for(int j=head[u];j!=-1;j=e[j].next){
55             int v=e[j].to;
56             if(vis[v]) sum++;//统计双连通分量内的边数
57         }
58     }
59     sum/=2;
60     if(sum>cc) ans2+=sum;//若边数大于点数,则为多个环
61 }
62 void init(){
63     cnt=id=top=0;
64     ans1=ans2=0;
65     memset(head,-1,sizeof(head));
66     memset(dfn,0,sizeof(dfn));
67     memset(low,0,sizeof(low));
68 }
69 int main()
70 {
71 
72     int u,v;
73     while(scanf("%d%d",&n,&m)==2&&n||m){
74         init();
75         while(m--){
76             scanf("%d%d",&u,&v);
77             add(u,v);
78             add(v,u);
79         }
80         for(int i=0;i<n;i++) if(!dfn[i]) dfs(i,-1);
81         printf("%d %d
",ans1,ans2);
82     }
83     return 0;
84 }
原文地址:https://www.cnblogs.com/mj-liylho/p/9560539.html