HDOJ 2767 Proving Equivalences(强连通算法入门)
题意:
一个有向图,问至少添加几条边让整个图变成强连通图。
思路:
1. 基本上是模板题,首先对有向图进行缩点,即把所有强连通分量看成是一个点,Targan 算法 http://www.byvoid.com/blog/scc-tarjan/
2. 统计出度和入度为 0 的点的个数,输出其中的最大的一个即可。
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
const int MAXN = 20010;
vector<int> G[MAXN];
stack<int> S;
int dfn[MAXN], low[MAXN], sccno[MAXN], tclock, scccnt;
int indeg[MAXN], outdeg[MAXN];
void targan(int u) {
dfn[u] = low[u] = ++tclock;
S.push(u);
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (!dfn[v]) {
targan(v);
low[u] = min(low[u], low[v]);
} else if (!sccno[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u]) {
scccnt += 1;
int v = -1;
while (v != u) {
v = S.top();
S.pop();
sccno[v] = scccnt;
}
}
}
void findscc(int n) {
tclock = scccnt = 0;
memset(sccno, 0, sizeof(int)*(n+1));
memset(dfn, 0, sizeof(int)*(n+1));
memset(low, 0, sizeof(int)*(n+1));
for (int i = 1; i <= n; i++)
if (!dfn[i]) targan(i);
}
int workout(int n) {
if (scccnt == 1)
return 0;
memset(indeg, 0, sizeof(int)*(n+1));
memset(outdeg, 0, sizeof(int)*(n+1));
for (int u = 1; u <= n; u++) {
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (sccno[u] != sccno[v]) {
indeg[sccno[v]] += 1;
outdeg[sccno[u]] += 1;
}
}
}
int c1 = 0, c2 = 0;
for (int i = 1; i <= scccnt; i++) {
if (indeg[i] == 0) c1 += 1;
if (outdeg[i] == 0) c2 += 1;
}
return max(c1, c2);
}
int main() {
int cases;
scanf("%d", &cases);
while (cases--) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
G[i].clear();
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
}
findscc(n);
printf("%d\n", workout(n));
}
return 0;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------