1. 程式人生 > >POJ 3177 - Redundant Paths - 雙連通分量

POJ 3177 - Redundant Paths - 雙連通分量

n) return class 註意 pair 標記 iterator 割邊 ()

題目大意:

給定一個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 }

POJ 3177 - Redundant Paths - 雙連通分量