题目大意:
给定一个N个点,M条边的无向连通图(可能有重边),要求让任意两点间都有两条或以上的路径,且这些路径没有公共边。问至少需要加多少条边?
N<=5e3,M<=1e4。
求双连通分量并缩点。详见:https://www.cnblogs.com/frog112111/p/3367039.html
注意由于本题数据允许重边(尽管讨论区有人吐槽数据太水),DFS时判断割边的条件应为low[to] > dfn[cur],且该边的重数为1。
实现的时候用了并查集来维护属于同一双联通分量的点,标记割边时将它的重数变成-1。
代码:(都8102年了贵OJ还不支持C++11-_-||)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <map> 5 6 using namespace std; 7 8 const int maxN = 5000 + 5; 9 const int notVisited = -1; 10 11 map<int, int> elist[maxN]; 12 int dfn[maxN]; 13 int low[maxN]; 14 int ufs[maxN]; 15 int cnt[maxN]; 16 int lastDfn = 0; 17 int N, M; 18 19 inline void addEdge(int u, int v) 20 { 21 map<int, int>::iterator it = elist[u].find(v); 22 if (it != elist[u].end()) 23 it->second += 1; 24 else 25 elist[u].insert(make_pair(v, 1)); 26 } 27 28 void input() 29 { 30 scanf("%d%d", &N, &M); 31 for (int u, v, i = 1; i <= M; i++) 32 { 33 scanf("%d%d", &u, &v); 34 addEdge(u, v); 35 addEdge(v, u); 36 } 37 } 38 39 void init() 40 { 41 memset(dfn, -1, sizeof(dfn)); 42 memset(low, 0x3f, sizeof(low)); //infinity 43 lastDfn = 0; 44 for (int i = 1; i <= N; i++) 45 ufs[i] = i; 46 } 47 48 int findUfs(int x) 49 { 50 return ufs[x] == x ? x : (ufs[x] = findUfs(ufs[x])); 51 } 52 53 bool unifyUfs(int x, int y) 54 { 55 int fx = findUfs(x); 56 int fy = findUfs(y); 57 if (fx == fy) 58 return false; 59 ufs[fx] = fy; 60 return true; 61 } 62 63 void dfs(int cur, int last) 64 { 65 dfn[cur] = low[cur] = (++lastDfn); 66 67 for (map<int, int>::iterator it = elist[cur].begin(); it != elist[cur].end(); ++it) 68 { 69 int to = it->first; 70 if (dfn[to] == notVisited) 71 { 72 dfs(to, cur); 73 if (it->second >= 2 || low[to] <= dfn[cur]) 74 unifyUfs(cur, to); 75 else 76 it->second = -1; 77 low[cur] = min(low[cur], low[to]); 78 } 79 else if (to != last) 80 { 81 unifyUfs(to, cur); 82 low[cur] = min(low[cur], dfn[to]); 83 } 84 } 85 } 86 87 int solve() 88 { 89 init(); 90 dfs(1, 0); 91 92 for (int i = 1; i <= N; i++) 93 for (map<int, int>::iterator it = elist[i].begin(); it != elist[i].end(); ++it) 94 { 95 if (it->second > 0) 96 continue; 97 98 int to = it->first; 99 int fi = findUfs(i); 100 int ft = findUfs(to); 101 if (fi != ft) 102 { 103 cnt[fi] += 1; 104 cnt[ft] += 1; 105 } 106 } 107 108 return ((int)count(cnt + 1, cnt + N + 1, 1) + 1) / 2; 109 } 110 111 int main() 112 { 113 input(); 114 printf("%d", solve()); 115 return 0; 116 }