【求无向图的桥,有重边】ZOJ

模板题——求割点与桥

题意,要使一个无向图不连通,输出必定要删掉的边的数量及其编号。求桥的裸题,可拿来练手。

套模板的时候注意本题两节点之间可能有多条边,而模板是不判重边的,所以直接套模板的话,会将重边也当做桥输出,因此要在判断桥的时候加一个判断,即当且仅当两点之间仅有一条边,且满足dfn[cur] < low[i],(cur, i)才是桥。

另外本题节点数为105,用邻接矩阵的话会内存超限,所以我用了了一个multiset存储边及其编号。

代码如下:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<vector>
 5 #include<set>
 6 #include<algorithm>
 7 #include<iostream>
 8 using namespace std;
 9 const int MAX_V = 10005;
10 const int MAX_E = 100005;
11 struct Edge
12 {
13     int to, id;
14     Edge() {}
15     Edge(int _t, int _i):to(_t), id(_i) {}
16     bool operator < (const Edge& rhs) const
17     {
18         return to < rhs.to;
19     }
20 };
21 multiset<Edge> edge[MAX_V];
22 multiset<int> tms[MAX_V];
23 vector<int> ans;
24 int vis[MAX_V]; //结点v当前访问状态,0表示未访问,1表示在栈中,2表示已经访问过
25 int dfn[MAX_V]; //结点v被访问时的深度
26 int low[MAX_V]; //结点v可以到达的访问时间最早的祖先的深度
27 void cut_bridge(int cur, int father, int dep, int n) //vertex: 0~n-1
28 {
29     vis[cur] = 1;
30     dfn[cur] = dep;
31     low[cur] = dep;
32     int children = 0;
33     int sz = edge[cur].size();
34     for(multiset<Edge>::iterator it = edge[cur].begin(); it != edge[cur].end(); it++)
35     {
36         int id = (*it).id;
37         int i = (*it).to;
38         if(i != father && vis[i] == 1) //i在当前栈中,说明图中有一个环,用i的深度更新cur的low值;
39         {
40             if(dfn[i] < low[cur]) low[cur] = dfn[i]; //将结点cur可以到达的访问时间最早的祖先的深度更新为结点i被访问时的深度;
41         }
42         if(vis[i] == 0) //i没被访问过,递归访问节点i,并用i的可以到达的最早祖先来更新cur的low值;
43         {
44             cut_bridge(i, cur, dep+1, n);
45             if(low[i] < low[cur]) low[cur] = low[i];
46             if(low[i] > dfn[cur] && tms[cur].count(i) == 1)
47             {
48                 ans.push_back(id);
49             }//判断桥
50         }
51     }
52     vis[cur] = 2;
53 }
54 void init(int n)
55 {
56     ans.clear();
57     memset(vis, 0, sizeof(vis));
58     for(int i = 0; i <= n; i++)
59     {
60         edge[i].clear();
61         tms[i].clear();
62     }
63 }
64 int main()
65 {
66     int T;
67     scanf("%d", &T);
68     for(int kase = 0; kase < T; kase++)
69     {
70         if(kase) printf("
");
71         int n, m;
72         scanf("%d%d", &n, &m);
73         init(n);
74         for(int i = 0; i < m; i++)
75         {
76             int u, v;
77             scanf("%d%d", &u, &v);
78             Edge e1(v, i+1), e2(u, i+1);
79             edge[u].insert(e1);
80             edge[v].insert(e2);
81             tms[u].insert(v);
82             tms[v].insert(u);
83         }
84         for(int i = 1; i <= n; i++)
85             if(vis[i] == 0)
86                 cut_bridge(i, -1, 1, n);
87 
88         sort(ans.begin(), ans.end());
89         printf("%d
", ans.size());
90         for(int i = 0; i < ans.size(); i++)
91         {
92             if(i) printf(" ");
93             printf("%d", ans[i]);
94         }
95         if(ans.size()) printf("
");
96     }
97     return 0;
98 }
ZOJ 2588
原文地址:https://www.cnblogs.com/LLGemini/p/4730961.html