zoukankan      html  css  js  c++  java
  • tarjan

    专业求解强连通分量边双连通分量点双连通分量缩点割点割边30年!

    “你是割点”

    “那你就是桥”

    “是的,我是一条归桥,想不到吧”

    首先是强连通分量缩点的tarjan。奉上代码。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <stack>
      4 
      5 const int N = 500010, INF = 0x7f7f7f7f;
      6 
      7 inline void read(int &x) {
      8     x = 0;
      9     char c = getchar();
     10     bool f = 0;
     11     while(c < '0' || c > '9') {
     12         if(c == '-') {
     13             f = 1;
     14         }
     15         c = getchar();
     16     }
     17     while(c >= '0' && c <= '9') {
     18         x = (x << 3) + (x << 1) + c - 48;
     19         c = getchar();
     20     }
     21     if(f) {
     22         x = (~x) + 1;
     23     }
     24     return;
     25 }
     26 
     27 struct Edge {
     28     int nex, v;
     29 }edge[N], scc_edge[N]; int tp, scc_tp;
     30 
     31 int stk[N], top;
     32 int e[N], scc_e[N], scc_cnt, val[N], scc_val[N], dfn[N], low[N], num;
     33 int n, m, fr[N], in[N], f[N];
     34 bool use[N], scc_use[N];
     35 
     36 inline void add(int x, int y) {
     37     tp++;
     38     edge[tp].v = y;
     39     edge[tp].nex = e[x];
     40     e[x] = tp;
     41     return;
     42 }
     43 
     44 inline void scc_add(int x, int y) {
     45     scc_tp++;
     46     scc_edge[scc_tp].v = y;
     47     scc_edge[scc_tp].nex = scc_e[x];
     48     scc_e[x] = scc_tp;
     49     return;
     50 }
     51 
     52 inline void exmin(int &a, const int &b) {
     53     a > b ? a = b : 0;
     54     return;
     55 }
     56 inline void exmax(int &a, const int &b) {
     57     a < b ? a = b : 0;
     58     return;
     59 }
     60 
     61 void tarjan(int x) {
     62     low[x] = dfn[x] = ++num;
     63     stk[++top] = x;
     64     for(int i = e[x]; i; i = edge[i].nex) {
     65         int y = edge[i].v;
     66         if(!dfn[y]) {
     67             tarjan(y);
     68             exmin(low[x], low[y]);
     69         }
     70         else if(!fr[y]) {
     71             exmin(low[x], dfn[y]);
     72         }
     73     }
     74     if(low[x] == dfn[x]) {
     75         scc_cnt++;
     76         int y;
     77         do {
     78             y = stk[top];
     79             top--;
     80             fr[y] = scc_cnt;
     81             scc_val[scc_cnt] += val[y];
     82             scc_use[scc_cnt] |= use[y];
     83         } while(y != x);
     84     }
     85     return;
     86 }
     87 
     88 int main() {
     89 
     90     //freopen("atm.in", "r", stdin);
     91     //freopen("atm.out", "w", stdout);
     92 
     93     read(n); read(m);
     94     for(int i = 1, x, y; i <= m; i++) {
     95         read(x); read(y);
     96         add(x, y);
     97     }
     98     for(int i = 1; i <= n; i++) {
     99         read(val[i]);
    100     }
    101     int s, k;
    102     read(s); read(k);
    103     for(int i = 1, x; i <= k; i++) {
    104         read(x);
    105         use[x] = 1;
    106     }
    107 
    108     tarjan(s);
    109     for(int x = 1; x <= n; x++) {
    110         if(!dfn[x]) {
    111             continue;
    112         }
    113         for(int i = e[x]; i; i = edge[i].nex) {
    114             int y = edge[i].v;
    115             if(fr[y] != fr[x]) {
    116                 scc_add(fr[x], fr[y]);
    117                 in[fr[y]]++;
    118             }
    119         }
    120     }
    121 
    122     memset(f, ~0x7f, sizeof(f));
    123     f[fr[s]] = 0;
    124     int ans = -INF;
    125     for(int i = 1; i <= scc_cnt; i++) {
    126         if(!in[i]) {
    127             stk[++top] = i;
    128         }
    129     }
    130     while(top) {
    131         int x = stk[top];
    132         top--;
    133         f[x] += scc_val[x];
    134         if(scc_use[x]) {
    135             exmax(ans, f[x]);
    136         }
    137         for(int i = scc_e[x]; i; i = scc_edge[i].nex) {
    138             int y = scc_edge[i].v;
    139             in[y]--;
    140             exmax(f[y], f[x]);
    141             if(!in[y]) {
    142                 stk[++top] = y;
    143             }
    144         }
    145     }
    146 
    147     printf("%d
    ", ans);
    148     return 0;
    149 }
    洛谷P3627 抢掠计划

    然后是边双连通分量的缩点和割边。

      1 #include <cstdio>
      2 #include <stack>
      3 
      4 const int N = 5010, M = 10010;
      5 
      6 struct Edge {
      7     int nex, v;
      8     bool cut;
      9 }ecc_edge[M << 1], edge[M << 1]; int tp = 1, ecc_tp;
     10 
     11 int e[N], low[N], dfn[N], num, fr[N], ecc_cnt, in[N], ecc_e[N], vis[N], leaf;
     12 std::stack<int> S;
     13 
     14 inline void ecc_add(int x, int y) {
     15     ecc_tp++;
     16     ecc_edge[ecc_tp].v = y;
     17     ecc_edge[ecc_tp].nex = ecc_e[x];
     18     ecc_e[x] = ecc_tp;
     19     return;
     20 }
     21 
     22 inline void add(int x, int y) {
     23     tp++;
     24     edge[tp].v = y;
     25     edge[tp].nex = e[x];
     26     e[x] = tp;
     27     return;
     28 }
     29 
     30 void DFS(int x, int f) {
     31     leaf += in[x] == 1;
     32     vis[x] = 1;
     33     for(int i = ecc_e[x]; i; i = ecc_edge[i].nex) {
     34         int y = ecc_edge[i].v;
     35         if(y != f) {
     36             DFS(y, x);
     37         }
     38     }
     39     return;
     40 }
     41 
     42 void tarjan(int x, int in_edge) {
     43     low[x] = dfn[x] = ++num;
     44     S.push(x);
     45     for(int i = e[x]; i; i = edge[i].nex) {
     46         int y = edge[i].v;
     47         if(!dfn[y]) {
     48             tarjan(y, i ^ 1);
     49             low[x] = std::min(low[x], low[y]);
     50             if(low[y] > dfn[x]) {
     51                 edge[i].cut = edge[i ^ 1].cut = 1;
     52             }
     53         }
     54         else if(i != in_edge) {
     55             low[x] = std::min(low[x], dfn[y]);
     56         }
     57     }
     58     if(low[x] == dfn[x]) {
     59         int y;
     60         ecc_cnt++;
     61         do {
     62             y = S.top();
     63             S.pop();
     64             fr[y] = ecc_cnt;
     65         } while(y != x);
     66     }
     67     return;
     68 }
     69 
     70 int main() {
     71 
     72     int n, m;
     73     scanf("%d%d", &n, &m);
     74     for(int i = 1, x, y; i <= m; i++) {
     75         scanf("%d%d", &x, &y);
     76         add(x, y); add(y, x);
     77     }
     78 
     79     for(int i = 1; i <= n; i++) {
     80         if(!dfn[i]) {
     81             tarjan(i, 0);
     82         }
     83     }
     84 
     85     for(int i = 2; i <= tp; i += 2) {
     86         int x = edge[i].v, y = edge[i ^ 1].v;
     87         if(fr[x] == fr[y]) {
     88             continue;
     89         }
     90         in[fr[x]]++;
     91         in[fr[y]]++;
     92         ecc_add(fr[x], fr[y]);
     93         ecc_add(fr[y], fr[x]);
     94     }
     95 
     96     int t = 0, ans = 0;
     97     for(int i = 1; i <= ecc_cnt; i++) {
     98         if(!vis[i]) {
     99             t++;
    100             leaf = 0;
    101             DFS(i, 0);
    102             ans += (leaf + 1) / 2;
    103         }
    104     }
    105 
    106     printf("%d
    ", ans + (t > 1) * t);
    107     return 0;
    108 }
    POJ3177 Redundant Paths

    然后是点双连通分量的缩点和割点。

     1 #include <cstdio>
     2 #include <algorithm>
     3 
     4 const int N = 20010, M = 100010;
     5 
     6 struct Edge {
     7     int nex, v;
     8 }edge[M << 1]; int tp = 1;
     9 
    10 int e[N], dfn[N], low[N], num, ans, cut[N];
    11 
    12 inline void add(int x, int y) {
    13     tp++;
    14     edge[tp].v = y;
    15     edge[tp].nex = e[x];
    16     e[x] = tp;
    17     return;
    18 }
    19 
    20 inline void tarjan(int x, int in_edge) {
    21     low[x] = dfn[x] = ++num;
    22     int cnt = 0;
    23     for(int i = e[x]; i; i = edge[i].nex) {
    24         int y = edge[i].v;
    25         if(!dfn[y]) {
    26             tarjan(y, i ^ 1);
    27             low[x] = std::min(low[x], low[y]);
    28             if(low[y] >= dfn[x]) { /// error : > 
    29                 cnt++;
    30             }
    31         }
    32         else if(i != in_edge) {
    33             low[x] = std::min(low[x], dfn[y]);
    34         }
    35     }
    36     if(cnt > 1 || (cnt == 1 && in_edge)) {
    37         cut[x] = 1;
    38         ans++;
    39     }
    40     return;
    41 }
    42 
    43 int main() {
    44     int n, m;
    45     scanf("%d%d", &n, &m);
    46     for(int i = 1, x, y; i <= m; i++) {
    47         scanf("%d%d", &x, &y);
    48         add(x, y); add(y, x);
    49     }
    50 
    51     for(int i = 1; i <= n; i++) {
    52         if(!dfn[i]) {
    53             tarjan(i, 0);
    54         }
    55     }
    56 
    57     printf("%d
    ", ans);
    58     for(int i = 1; i <= n; i++) {
    59         if(cut[i]) {
    60             printf("%d ", i);
    61         }
    62     }
    63 
    64     return 0;
    65 }
    洛谷P3388 割点
  • 相关阅读:
    分布式计算原理
    消息的有序性
    CAP再解释
    数据建模
    领导层级的跨越
    如何上云|什么是多机房多活架构
    mysql导出导入数据
    Qt 串口 封装好的类 直接使用
    C++ 在类的定义时初始化非静态变量
    Qt error C3646: 未知重写说明符
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10424342.html
Copyright © 2011-2022 走看看