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\n", 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\n", 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\n", 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 割点

 

转载于:https://www.cnblogs.com/huyufeifei/p/10424342.html

项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还[基于Python]自己写的一个微信跳一跳自动游戏程序(针对安卓手机)。 全自动运行 自动适应不同分辨率 自动调整各个参数误差.zip行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值