POJ 3177 Redundant Paths(强连通分量)

题目链接:http://poj.org/problem?id=3177

题目大意是一个无向图给你n个点m条边,让你求出最少加多少条边 可以让任意两个点相通两条及以上的路线(每条路线点可以重复,但是每条路径上不能有重边),简单来说就是让你加最少的边使这个图变成一个双连通图。

首先用tarjan来缩点,可以得到一个新的无环图,要是只有一个强连通分量,那本身就是一个双连通图。要是多个强连通分量,那我们可以考虑缩点后度数为1的点(肯定是由这个点开始连新边最优),那我们假设数出度数为1的点的个数为cnt,可以画几个图观察可得答案就是(cnt + 1) / 2。但是这题有个问题就是要去掉重边(A B和B A不算重边),不然会wa...,所以我用了二维map来去重边。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #include <map>
 6 using namespace std;
 7 const int MAXN = 5005;
 8 map <int , map<int , int> > mp;
 9 struct data {
10     int next , to;
11 }edge[MAXN * 5];
12 int head[MAXN] , low[MAXN] , dfn[MAXN] , st[MAXN] , block[MAXN] , du[MAXN];
13 int top , ord , sccnum , cont;
14 bool instack[MAXN];
15 
16 void init() {
17     memset(head , -1 , sizeof(head));
18     memset(instack , false , sizeof(instack));
19     memset(low , 0 , sizeof(low));
20     memset(dfn , 0 , sizeof(dfn));
21     memset(du , 0 , sizeof(du));
22     top = ord = sccnum = cont = 0;
23 }
24 
25 void add(int u , int v) {
26     edge[cont].next = head[u];
27     edge[cont].to = v;
28     head[u] = cont++;
29 }
30 
31 void tarjan(int u , int par) {
32     low[u] = dfn[u] = ++ord;
33     st[++top] = u;
34     instack[u] = true;
35     for(int i = head[u] ; ~i ; i = edge[i].next) {
36         int v = edge[i].to;
37         if(v == par)
38             continue;
39         if(!dfn[v]) {
40             tarjan(v , u);
41             low[u] = min(low[u] , low[v]);
42         }
43         else if(instack[v]) {
44             low[u] = min(low[u] , dfn[v]);
45         }
46     }
47     if(low[u] == dfn[u]) {
48         int v;
49         sccnum++;
50         do {
51             v = st[top--];
52             instack[v] = false;
53             block[v] = sccnum;
54         }while(u != v);
55     }
56 }
57 
58 int main()
59 {
60     int n , m , u , v;
61     while(~scanf("%d %d" , &n , &m)) {
62         init();
63         mp.clear();
64         while(m--) {
65             scanf("%d %d" , &u , &v);
66             if(!mp[u][v]) {
67                 add(u , v);
68                 add(v , u);
69                 mp[u][v]++;
70             }
71         }
72         tarjan(1 , -1);
73         for(int u = 1 ; u <= n ; u++) {
74             for(int i = head[u] ; ~i ; i = edge[i].next) {
75                 int v = edge[i].to;
76                 if(block[u] != block[v]) {
77                     du[block[u]]++;
78                 }
79             }
80         }
81         int res = 0;
82         for(int i = 1 ; i <= sccnum ; i++) {
83             if(du[i] == 1)
84                 res++;
85         }
86         printf("%d
" , (res + 1) / 2);
87     }
88 }
原文地址:https://www.cnblogs.com/Recoder/p/5263534.html