码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 3177 - Redundant Paths - 双连通分量

时间:2018-02-18 12:37:20      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:air   include   双连通分量   缩点   blog   begin   pre   联通   frog   

题目大意:

给定一个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 - 双连通分量

标签:air   include   双连通分量   缩点   blog   begin   pre   联通   frog   

原文地址:https://www.cnblogs.com/Onlynagesha/p/8452656.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!