zoukankan      html  css  js  c++  java
  • poj 3177 Redundant Paths 求最少添加几条边成为双联通图: tarjan O(E)

      1 /**
      2 problem: http://poj.org/problem?id=3177
      3 tarjan blog: https://blog.csdn.net/reverie_mjp/article/details/51704523
      4 
      5 v 为下一结点, u为当前结点
      6 如果low[v] > dfn[u] 则 边(u,v)为桥
      7 缩点后剩下的所有边都为桥(缩点后即为树结构)
      8 将叶子结点相连使其成为双联通分量为最优解
      9 所以:
     10 添加(leaf + 1) / 2 条边即可使图成为双联通图
     11 **/
     12 #include<stdio.h>
     13 #include<stack>
     14 #include<algorithm>
     15 using namespace std;
     16 
     17 class Graphics{
     18     const static int MAXN = 5005;
     19     const static int MAXM = 10005 * 2;
     20 private:
     21     struct Edge{
     22         int to, next;
     23         bool bridge;
     24     }edge[MAXM];
     25     struct Point{
     26         int dfn, low, color;
     27     }point[MAXN];
     28     int first[MAXN], sign, sumOfPoint, dfnNum, colorNum;
     29     bool vis[MAXN];
     30     stack<int> stk;
     31     void tarjan(int u, int preEdge = -1){
     32         point[u].low = dfnNum;
     33         point[u].dfn = dfnNum ++;
     34         vis[u] = true;
     35         stk.push(u);
     36         for(int i = first[u]; i != -1; i = edge[i].next){
     37             int to = edge[i].to;
     38             if((i^1) == preEdge) continue; /// 由于是双向边,防止由该边跑回原来的点
     39             if(!point[to].dfn){
     40                 tarjan(to, i);
     41                 point[u].low = min(point[u].low, point[to].low);
     42                 if(point[to].low > point[u].dfn){
     43                     edge[i].bridge = true;
     44                     edge[i^1].bridge = true;
     45                 }
     46             }else if(vis[to]){
     47                 point[u].low = min(point[to].dfn, point[u].low);
     48             }
     49         }
     50         if(point[u].dfn == point[u].low){
     51             vis[u] = false;
     52             point[u].color = ++ colorNum;
     53             while(stk.top() != u){
     54                 point[stk.top()].color = colorNum;
     55                 vis[stk.top()] = false;
     56                 stk.pop();
     57             }
     58             stk.pop();
     59         }
     60     }
     61 public:
     62     void init(int n){
     63         sumOfPoint = n;
     64         for(int i = 1; i <= n; i ++){
     65             first[i] = -1;
     66             vis[i] = 0;
     67         }
     68         sign = colorNum = 0;
     69         dfnNum = 1;
     70     }
     71     void addEdgeOneWay(int u, int v){
     72         edge[sign].to = v;
     73         edge[sign].next = first[u];
     74         edge[sign].bridge = false;
     75         first[u] = sign ++;
     76     }
     77     void addEdgeTwoWay(int u, int v){
     78         addEdgeOneWay(u, v);
     79         addEdgeOneWay(v, u);
     80     }
     81     void tarjanAllPoint(){
     82         for(int i = 1; i <= sumOfPoint; i ++){
     83             if(!point[i].dfn)
     84                 tarjan(i);
     85         }
     86     }
     87     int getAns(){
     88         int *degree = new int[sumOfPoint+1];
     89         int ans = 0;
     90         for(int i = 1; i <= sumOfPoint; i ++){
     91             degree[i] = 0;
     92         }
     93         tarjanAllPoint();
     94         for(int i = 1; i <= sumOfPoint; i ++){
     95             for(int j = first[i]; j != -1; j = edge[j].next){
     96                 int to = edge[j].to;
     97                 if(edge[j].bridge){
     98                     degree[point[to].color] ++;
     99                 }
    100             }
    101         }
    102         for(int i = 1; i <= sumOfPoint; i ++){
    103             if(degree[i] == 1){
    104                 ans ++;
    105             }
    106         }
    107         delete []degree; return (ans + 1) / 2;
    108     }
    109 }graph;
    110 
    111 int main(){
    112     int f, r;
    113     scanf("%d%d", &f, &r);
    114     graph.init(f);
    115     while(r --){
    116         int a, b;
    117         scanf("%d%d", &a, &b);
    118         graph.addEdgeTwoWay(a, b);
    119     }
    120     printf("%d
    ", graph.getAns());
    121     return 0;
    122 }

    ps:

    防止由该边跑回原来的点不能判断(点)而要判断(边)即

    这么写是有bug的
    例如:重边

  • 相关阅读:
    350 Intersection of Two Arrays II 两个数组的交集 II
    349 Intersection of Two Arrays 两个数组的交集
    347 Top K Frequent Elements 前K个高频元素
    345 Reverse Vowels of a String 反转字符串中的元音字母
    344 Reverse String 反转字符串
    343 Integer Break 整数拆分
    342 Power of Four 4的幂
    338 Counting Bits Bit位计数
    Java常见面试题之Forward和Redirect的区别
    字节、字、bit、byte的关系
  • 原文地址:https://www.cnblogs.com/DarkScoCu/p/10527080.html
Copyright © 2011-2022 走看看