Equivalent Sets HDU - 3836(tarjan缩点)
作者:互联网
题意
一张有向图,需要至少连多少条边使得这个图强联通
思路
缩点成一张拓扑图,问题就转化成,至少需要加几条边使得这个拓扑图变成一张强联通图。设p为拓扑图入度为0的点的个数,q为出度为0的点的个数,需要加的边数就是max(p,q)。证明略(我不会)。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<stack>
using namespace std;
const int MAX_N = 20010;
const int MAX_M = 50010;
struct edge {
int v, nxt;
}e[MAX_M];
int n, m;
int dfn[MAX_N], low[MAX_N], timestamp;
int head[MAX_M], cnt = 1;
int id[MAX_N], scc_cnt;
int in_stack[MAX_N];
int din[MAX_N], dout[MAX_N];
stack<int>S;
void init() {
memset(dfn, 0, sizeof dfn);
memset(id, 0, sizeof id);
memset(low, 0, sizeof low);
memset(head, -1, sizeof head);
memset(in_stack, 0, sizeof in_stack);
memset(din, 0, sizeof din);
memset(dout, 0, sizeof dout);
scc_cnt = 0, cnt = 1, timestamp = 0;
while (!S.empty())S.pop();
}
void add(int u, int v) {
e[cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
void tarjan(int u) {
dfn[u] = low[u] = ++timestamp;
S.push(u);
in_stack[u] = true;
for (int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].v;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (in_stack[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
++scc_cnt;
while (1) {
int y = S.top();
in_stack[y] = false;
S.pop();
id[y] = scc_cnt;
if (y == u)break;
}
}
}
int main() {
while (scanf("%d%d", &n, &m) != EOF) {
init();
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i])tarjan(i);
}
for (int i = 1; i <= n; i++) {
for (int j = head[i]; ~j; j = e[j].nxt) {
int v = e[j].v;
int a = id[i], b = id[v];
if (a != b) {
dout[a]++;
din[b]++;
}
}
}
int a = 0;
int b = 0;
for (int i = 1; i <= scc_cnt; i++) {
if (!din[i])a++;
if (!dout[i])b++;
}
if (scc_cnt == 1)cout << 0 << endl;
else
cout << max(a, b) << endl;
}
return 0;
}
标签:缩点,tarjan,int,MAX,Equivalent,memset,cnt,dfn,low 来源: https://blog.csdn.net/qq_43560101/article/details/104842123